自动化测试或爬虫脚本场景经常需要模拟用户向手机设备发送各种交互事件,最常见的就是点击事件,这里面就有一个大前提就是你需要获取点击位置的 x、y 屏幕坐标。
如何获取以及如何发送事件,这里涉及到 Android 系统提供的 getevent 和 sendevent 操作知识点。
通过 getevent 和 sendevent 命令可以查看和触发系统的操作事件,包括触摸屏事件和虚拟物理按键事件。除此之外,input 命令也可以做到发送指令。
getevent
我们使用 USB 连接一台安卓手机设备后,通过 adb shell
进入 shell 交互式环境,输入命令 getevent -help
可以查看 getevent 命令的参数介绍:
|
|
参数很多,都有对应的英文解释,比如 -t 表示显示事件发生的事件,-l 表示显示事件类型和名称。我们先不加任何参数,了解一下 getevent 命令的用法。
执行 getevent
命令,开始查看接收到的事件信息。开头这一系列 add device 输入表示当前设备支持的事件类型。
|
|
备注:上面打印的这段设备信息,通过执行 getevent -p
命令行也能拿到,需要注意的是,里面有个屏幕尺寸信息:
|
|
其实是不准确的,不能直接拿来用的,获取屏幕分辨率等信息还是要通过这个命令获取:
|
|
或者更简洁一点的:
|
|
说回正题,开始监听事件后,我们按一下手机音量上键,就会得到这么一段输入信息:
|
|
每一行代表一条指令,每条指令从左到右,依次表示:设备名称、事件类型、事件编码和事件携带的数据(十六进制表示)。
设备名称可以从 getevent 命令开头的一段输出中找到,事件类型和事件编码可以在 android 系统内核源码中对照查看: include/linux/input.h,源码仓库 git 地址为:
比如,input.h 文件中定义的事件类型有这些(十六进制):
|
|
可以看到,前面我们操作的音量上键使用到了 EV_SYN 和 EV_KEY 两个类型,对应 input.h 定义的事件编码(十进制)为:
|
注意,对比查看事件编码时,需要进行十六进制与十进制的转换,可以找个在线工具,比如:
https://tool.oschina.net/hexconvert
这样对比下来,我们就能理解 getevent
不带任何参数时输出信息的含义。不过还是有点繁琐,不如直接给到事件名字更加清晰一些。
比如,使用 -l
参数直接打印事件名称,再来看下同样的音量上键对应的输出信息,这样看起来是不是舒服多了:
|
|
同样的,我们看下添加 -l
参数前后,手指触摸屏幕的事件输出情况。这是 getevent
命令下触摸屏幕的输出信息:
|
|
翻译一下,十六进制 0003 对应的事件类型为 EV_ABS,表示触摸屏幕对应的坐标相关数据,input.h 文件中的定义有:
|
其实我们比较常用的就是触摸中心点的屏幕绝对坐标 x、y 值。添加 -l
参数,再来操作一遍,看下 getevent -l
命令的输出信息:
|
|
除了两次触摸屏幕引发的事件携带数据上非常小的 x、y 值差异外,其他都是一样的。
sendevent
了解完 getevent 获取事件,通过 sendevent 就能够发送事件。还是使用 help 参数先看下介绍和用法:
|
|
可以看到,sendevent 命令需要的四个参数(设备、类型、编码和数据)刚好就是 getevent 命令获取到的。
那么模拟前面获取到的触摸屏幕事件,就是执行这样一组指令(需要全部完整执行完一组,不同手机设备参数也不同):
|
|
需要注意的是,真机设备测试中,可能会遇到 sendevent 不起作用的情况,可能是没有 input 目录文件写入权限的问题,试着修改一下:
|
|
input
sendevent 命令通过一组命令才能完成一个事件,而且参数复杂。相比较而言,input 命令就简单直接多了。
|
|
比如,向手机上已经获取焦点的输入框输入一段文本内容,就是这样:
|
|
再比如,发送触摸屏幕事件,使用 tap 命令,提供 x、y 坐标即可:
|
|
input 命令还有 swipe、press 等其他用法,这里就不一一介绍了。
注意事项
前面提到的 getevent、sendevent 和 input 操作事件的命令,在部分手机上还存在另一个操作权限的问题。
如果你在操作时遇到这样的提示信息,比如 getevent 命令遇到权限拒绝提示:
|
|
input 命令遇到 killed 提示信息:
|
|
这个时候,只需要到手机「开发者选项」设置中,找到 USB 调试模块中的这个选项:
USB调试(安全设置)
按照提示,一步步操作,打开即可。