在Android 中,有些特定的功能或者在调试的时候需要模拟屏幕点击功能和物理按键等。
在实现上有2种方式:
首先是模拟屏幕点击的实现方式有两种:
模拟屏幕点击
- 本进程内实现,就是只有在自己的app上面实现。
- 跨进程实现,就是模拟点击手机屏幕的某个坐标。
不跨进程实现方式:
假如我们需要模拟点击某个按钮,这时候可以使用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();
}
这实现原理就是模拟两个MotionEvent (按下和提起) 然后用一个View 来处理这个Event 。 这样就实现了模拟点击的操作,但是此种方式限制太大。本人觉得并没有什么用。
跨进程方式
跨进程方式其实就是整个手机系统中点击屏幕,并不局限于在某一个app内。
这种情况只能适用于已经ROOT的手机,通过执行shell命令来执行模拟操作。
- getevent 命令 & sendevent 命令
工具的源码位于Android SDK的system/core/toolbox下(sendevent.c getevent.c)。
首先我这里模拟用adb命令模拟一次操作,Window 系统下进入cmd命令行:
执行 :
adb shell getevent
输出内容为:
add device 1: /dev/input/event4
name: ""
add device 2: /dev/input/event0
name: "Ft5x_dev"
add device 3: /dev/input/event5
name: "tegra-max98095 Headphone Jack"
add device 4: /dev/input/event6
name: "gpio-keys"
add device 5: /dev/input/event7
name: "Accelerometer"
could not get driver version for /dev/input/js0, Invalid argument
add device 6: /dev/input/event2
name: "compass"
add device 7: /dev/input/event3
name: "gyro"
add device 8: /dev/input/event1
name: "taos"
上面输出信息为设备名称和设备的属性,如果命令添加 -p 参数的话,就会显示详细信息。
这时候我们如果触摸手机屏幕或者按了物理按键的时候,命令窗口就会打印出信息:
如下:
/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
这写命令就是我们的操作的命令,输出格式为 : device type code value
下面一一讲解上面参数的意义:
- dev/input/event0指的是处理触摸和按键的输入设备。
- 0003 指的是事件类型,EV_SYN [0000] (同步事件),EV_KEY [0001] (按键事件),EV_ABS [0003] (绝对值事件)
- code 指的是0003代表的事件中支持的编码。具体代表就我这里就不写出来。
- value 指的是值。
上面的getevent 命令的作用是查看输入设备和查看事件。
下面说说sendevent的功能。
用法为:adb shell sendevent device type code value
看到这里,其实我们已经能实现功能了,比如,我要模拟点击一下home 键,首先我用getevent命令的到点击这个HOME键的事件,我在用sendevent命令在发送一次同样的事件过去就实现了模拟再次点击HOMT键了。
下面说另一中方式:
模拟点击的功能通常都是使用 /dev/input/event0 这个输入设备
假如我需要模拟一次点击BACK键:
back键的类型为 0001(按键事件)
根据getevent - p 输出支持的信息可知BACK的编码为 0x9e 转换为十进制后即158(注意:sendevent 使用的进制是十进制)
那我们输入如下命令即可模拟一次BACK键的按下和弹起:
adb shell sendevent /dev/input/event0 1 158 1
adb shell sendevent /dev/input/event0 1 158 0
input keyevent 命令
这个命令也可以模拟按键操作,使用格式为:input keyevent code
几个常用的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 菜单
input text 命令
这个命令是用来向输入框输入内容的。后面参数为 “字符串”
input tap 命令
这个命令为模拟单击事件 后面参数为: x y
比如在 30,30 单击一下 : input tap 30 30
input swipe 命令
此命令为滑动事件。
比如我要从 30 10 滑动到 30 100 : input swipe 30 10 30 100
最后说明一下如何用代码实现:
/**
* 执行shell命令
*
* @param cmd
*/
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();
}
}