• Android 模拟点击


    Android 模拟点击

    1.通过代码的方式实现

    通过模拟MotionEvent的方式实现

    //----------------模拟点击---------------------
    private void simulateClick(View view, float x, float y) {
        long downTime = SystemClock.uptimeMillis();
        final MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0);
        downTime += 1000;
        final MotionEvent upEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_UP, x, y, 0);
        view.onTouchEvent(downEvent);
        view.onTouchEvent(upEvent);
        downEvent.recycle();
        upEvent.recycle();
    }
    
    public void setMouseClick1(int x, int y) {
        MotionEvent evenDownt = MotionEvent.obtain(System.currentTimeMillis(),
                    System.currentTimeMillis() + 100, MotionEvent.ACTION_DOWN, x, y, 0);
        dispatchTouchEvent(evenDownt);
        MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(),
                    System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, x, y, 0);
        dispatchTouchEvent(eventUp);
        evenDownt.recycle();
        eventUp.recycle();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    通过模拟Instrumentation测试的方式实现

    new Thread(() -> {
        Instrumentation inst = new Instrumentation();
        inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_DOWN, x, y, 0));
        inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_UP, x, y, 0));
    }).start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Instrumentation不能在主线程中使用

    java.lang.RuntimeException: This method can not be called from the main application thread
    
    • 1

    通过模拟adb命令的方式实现

    try {
        List orders = new ArrayList<>();
        orders.add("input");
        orders.add("tap");
    
        int[] location = new int[2];
        view.getLocationInWindow(location);
    
        int x = location[0];
        int y = location[1];
    
        orders.add("" + (x + 10));
        orders.add("" + (y + 10));
    
        new ProcessBuilder(orders).start();
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    相当于执行 adb 的命令,input tap x y x和y是坐标

    2.通过adb的方式实现

    一共就2步

    1.打开终端,输入adb shell

    2.执行模拟点击命令

    1、查看命令

    MassageRobotTCL>adb shell
    Lacus_12:/ # input
    Usage: input [] [-d DISPLAY_ID] […]

    The sources are:
    dpad
    keyboard
    mouse
    touchpad
    gamepad
    touchnavigation
    joystick
    touchscreen
    stylus
    trackball

    -d: specify the display ID.
    (Default: -1 for key event, 0 for motion event if not specified.)
    The commands and default sources are:
    text (Default: touchscreen)
    keyevent [–longpress] … (Default: keyboard)
    tap (Default: touchscreen)
    swipe [duration(ms)] (Default: touchscreen)
    draganddrop [duration(ms)] (Default: touchscreen)
    press (Default: trackball)
    roll (Default: trackball)
    motionevent (Default: touchscreen)
    Lacus_12:/ #
    Lacus_12:/ # input tap 1002 922
    Lacus_12:/ # input tap 1002 900
    Lacus_12:/ # input keyevent 4

    2、getevent -h 用法说明

    shell@hwH60:/ $ getevent -h  
    
    Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]
        -t: show time stamps
        -n: don't print newlines
        -s: print switch states for given bits
        -S: print all switch states
        -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)
        -d: show HID descriptor, if available
        -p: show possible events (errs, dev, name, pos. events)
        -i: show all device info and possible events
        -l: label event types and names in plain text
        -q: quiet (clear verbosity mask)
        -c: print given number of events then exit
        -r: print rate events are received
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    [-t] 参数显示事件的时间戳
    [-n] 取消事件显示时的换行符
    [-s switchmask] 得到指定位的开关状态
    [-S] 得到所有开关的状态
    [-v [mask]] 根据mask的值显示相关信息
    [-p] 显示每个设备支持的事件类型和编码
    [-q] 只显示事件数据
    [-c count] 只显示count次事件的数据
    [-r] 显示事件接收频率

    3、getevent -p 显示出来当前系统存在的所有input设备,并且把每个设备支持的事件类型以及编码

    shell@hwH60:/ $ getevent -p
    
    add device 1: /dev/input/event2
      name:     "hi6421_on"
      events:
        KEY (0001): 0074 
      input props:
        
    could not get driver version for /dev/input/mouse0, Not a typewriter
    add device 2: /dev/input/event4
      name:     "huawei,touchscreen"
      events:
        KEY (0001): 003b  003c  003d  003e  003f  0040  0041  0042 
                    0043  0044  0057  00bd  00be  00bf  00c0  00c1 
                    0145  014a 
        ABS (0003): 0000  : value 0, min 0, max 1079, fuzz 0, flat 0, resolution 0
                    0001  : value 0, min 0, max 1919, fuzz 0, flat 0, resolution 0
                    0018  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                    0030  : value 0, min 0, max 15, fuzz 0, flat 0, resolution 0
                    0035  : value 0, min 0, max 1079, fuzz 0, flat 0, resolution 0
                    0036  : value 0, min 0, max 1919, fuzz 0, flat 0, resolution 0
                    0039  : value 0, min 0, max 15, fuzz 0, flat 0, resolution 0
                    003a  : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
      input props:
        INPUT_PROP_DIRECT
    add device 3: /dev/input/event0
      name:     "mhl_rcp_dev"
      events:
        KEY (0001): 0002  0003  0004  0005  0006  0007  0008  0009 
                    000a  000b  000e  001c  0034  003b  003c  003d 
                    003e  003f  0067  0069  006a  006c  0071  0072 
                    0073  0077  0080  008b  009e  009f  00a1  00a4 
                    00a5  00a7  00a8  00ae  00c8  00c9  00cf  00d0 
                    00d5  00e8  0161  0163  0192  0193  019c 
      input props:
        
    could not get driver version for /dev/input/mice, Not a typewriter
    add device 4: /dev/input/event1
      name:     "hisi_gpio_key.14"
      events:
        KEY (0001): 0072  0073 
      input props:
        
    add device 5: /dev/input/event3
      name:     "hi3630_hi6401_CARD Headset Jack"
      events:
        KEY (0001): 0072  0073  00e2 
        SW  (0005): 0002  0004 
      input props:
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    4、getevent 查看输入设备和查看事件

    打印输出log日志,等待输入设备,我们触摸屏幕或是手机物理按键,便会看到这里的变化

    shell@hwH60:/ $ getevent
    
    例如:
    /dev/input/event0: 0001 014a 00000001
    /dev/input/event0: 0003 0000 000000f6
    /dev/input/event0: 0003 0001 000002ed
    /dev/input/event0: 0003 0035 000000f6
    /dev/input/event0: 0003 0036 000002ed
    /dev/input/event0: 0003 0032 00000001
    /dev/input/event0: 0003 0039 00000000
    /dev/input/event0: 0003 003a 00000043
    /dev/input/event0: 0000 0002 00000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    他们四个参数对应的是device type code value
    device:指的是处理触摸和按键的输入设备。
    type:指的是事件类型,EV_SYN [0000] (同步事件),EV_KEY [0001] (按键事件),EV_ABS [0003] (绝对值事件)
    code 指的是前面type代表的事件中支持的编码。
    value 指的是值。

    例如:需要模拟一次点击BACK键,模拟点击的功能通常都是使用 /dev/input/event0 这个输入设备,back键的类型为 0001(按键事件),BACK的编码为 0x9e 转换为十进制后即158

    注意的是在getevent中code显示的是十六进制,而sendevent时需要用十进制

    那我们输入如下命令即可模拟一次BACK键的按下和弹起:

    adb shell sendevent /dev/input/event0 1 158 1
    adb shell sendevent /dev/input/event0 1 158 0
    
    • 1
    • 2

    5、input keyevent 命令

    先列举 input keyevent 几个比较常用的code值:

    input keyevent 3    // Home
    
    input keyevent 4    // Back
    
    input keyevent 19  //Up
    
    input keyevent 20  //Down
    
    input keyevent 21  //Left
    
    input keyevent 22  //Right
    
    input keyevent 23  //Select/Ok
    
    input keyevent 24  //Volume+
    
    input keyevent 25  // Volume-
    
    input keyevent 82  // Menu 菜单
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    例如:

    点击back键

    shell@hwH60:/ $ input keyevent 3 
    
    • 1

    input text 命令
    输入框输入内容的。后面参数为 “字符串”,例如输入”helloworld”字符串

    shell@hwH60:/ $ input text "helloworld!"
    
    • 1

    input tap 命令
    模拟单击事件 后面参数为: x y ,例如点击(168,252)位置

    shell@hwH60:/ $ input tap 168 252  
    
    • 1

    input swipe 命令
    此命令为滑动事件。例如:从 30 10 滑动到 30 100

    shell@hwH60:/ $ input swipe 30 10 30 100
    
    • 1

    Android代码实现,注意需要root

    private void execShellCmd(String cmd) {  
        try {  
            // 申请获取root权限,这一步很重要,不然会没有作用  
            Process process = Runtime.getRuntime().exec("su");  
            // 获取输出流  
            OutputStream outputStream = process.getOutputStream();  
            DataOutputStream dataOutputStream = new DataOutputStream(  
                    outputStream);  
            dataOutputStream.writeBytes(cmd);  
            dataOutputStream.flush();  
            dataOutputStream.close();  
            outputStream.close();  
        } catch (Throwable t) {  
            t.printStackTrace();  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    execShellCmd("getevent -p");  
    execShellCmd("sendevent /dev/input/event0 1 158 1");  
    execShellCmd("sendevent /dev/input/event0 1 158 0");  
    execShellCmd("input keyevent 3");//home  
    execShellCmd("input text  'helloworld!' ");  
    execShellCmd("input tap 168 252");  
    execShellCmd("input swipe 100 250 200 280");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    
    
    • 1

    3.关于x、y坐标的获取

    获取view的相对于屏幕中的坐标

    要获取View相对于屏幕的坐标,可以使用getLocationOnScreen()方法。以下是一个示例代码:

    View view = findViewById(R.id.my_view);
    
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    
    int x = location[0];
    int y = location[1];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在上述示例中,首先获取要获取坐标的View对象。然后创建一个长度为2的整型数组。接下来,使用getLocationOnScreen()方法将View的相对于屏幕的坐标存储到数组中。最后,通过数组的元素获取x和y坐标。请注意,x和y坐标是相对于屏幕的像素位置,以左上角为原点。

    如果要获取View相对于父容器的坐标,可以使用getLocationInWindow()方法。以下是一个示例代码:

    View view = findViewById(R.id.my_view);
    
    int[] location = new int[2];
    view.getLocationInWindow(location);
    
    int x = location[0];
    int y = location[1];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在上述示例中,使用的方法和步骤与获取相对于屏幕的坐标相同,只是获取的是相对于父容器的坐标。请注意,x和y坐标是相对于父容器的像素位置,以左上角为原点。

    这里的y坐标为什么和view.getY不一样?

    对于获取View的坐标,getY()方法返回的是View相对于父容器(即包含该View的布局容器)的y坐标。而getLocationOnScreen()方法返回的是View相对于整个屏幕的坐标。

    这两个方法返回的坐标值可能不同的原因是,View的坐标是相对于其父容器的坐标系的,而父容器在屏幕上的位置是可能发生变化的。当父容器发生位置变化时(例如滚动、动画等),View相对于父容器的坐标会发生相应的变化。而getLocationOnScreen()方法返回的是View相对于屏幕的坐标,不受父容器位置变化的影响。

    因此,如果你需要获取View相对于屏幕的坐标,应该使用getLocationOnScreen()方法。如果需要获取View相对于父容器的坐标,可以使用getX()和getY()方法。请根据具体的需求选择合适的方法来获取坐标。

    4.通过使用sendevent的方式实现

    adb提供了控制手机的另一种实现: sendevent [device] [type] [code] [value]

    eg:229就是menu的type值

    sendevent /dev/input/event0 1 229 1
    sendevent /dev/input/event0 1 229 0
    
    • 1
    • 2

    这两句需要一起执行,因为一个点击事件包含down和up,不然不能执行操作。

    这种方式不推荐,使用命令靠谱。除非你知道type值。

    5.参考

    Android代码模拟物理、屏幕点击事件 、APP内部自动点击

    Android模拟点击的四种方式

    Android模拟屏幕点击

  • 相关阅读:
    JS Set和Map数据结构
    uniapp微信小程序图片裁剪插件,支持自定义尺寸、定点等比例缩放、拖动、图片翻转、剪切圆形/圆角图片、定制样式
    Packet Tracer中交换机的配置及Lab2实验
    Windows使用一些问题的注意事项(包括换设备备份)和乱七八糟
    用色彩活出彩,能率Color Run上海之旅圆满结束
    使用Eclipse搭建Hadoop编程环境
    opencv 提取选中区域内指定hsv颜色的水印
    最大似然估计,散度,交叉熵
    nodejs express vue 酒店预订系统源码
    以太坊账户私钥管理之导出、导出keystore 文件
  • 原文地址:https://blog.csdn.net/fromVillageCoolBoy/article/details/133682078