Airtest
首先需要安装 Airtest,使用 pip3 即可:
1 |
pip3 install airtest |
初始化 device
如果设备没有被初始化的话会进行初始化,并把初始化的设备作为当前设备。 用法如下:
1 |
def init_device(platform="Android", uuid=None, **kwargs): |
示例如下:
1 |
device = init_device('Android') |
运行结果如下:
1 |
<airtest.core.android.android.Android object at 0x1018f3a58> |
可以发现它返回的是一个 Android 对象。 这个 Android 对象实际上属于 airtest.core.android
这个包,继承自 airtest.core.device.Device
这个类,与之并列的还有 airtest.core.ios.ios.IOS
、airtest.core.linux.linux.Linux
、airtest.core.win.win.Windows
等。这些都有一些针对 Device 操作的 API,下面我们以 airtest.core.android.android.Android
为例来总结一下。
- get_default_device:获取默认 device
- uuid:获取当前 Device 的 UUID
- list_app:列举所有 App
- path_app:打印输出某个 App 的完整路径
- check_app:检查某个 App 是否在当前设备上
- start_app:启动某个 App
- start_app_timing:启动某个 App,然后计算时间
- stop_app:停止某个 App
- clear_app:清空某个 App 的全部数据
- install_app:安装某个 App
- install_multiple_app:安装多个 App
- uninstall_app:卸载某个 App
- snapshot:屏幕截图
- shell:获取 Adb Shell 执行的结果
- keyevent:执行键盘操作
- wake:唤醒当前设备
- home:点击 HOME 键
- text:向设备输入内容
- touch:点击屏幕某处的位置
- double_click:双击屏幕某处的位置
- swipe:滑动屏幕,由一点到另外一点
- pinch:手指捏和操作
- logcat:日志记录操作
- getprop:获取某个特定属性的值
- get_ip_address:获取 IP 地址
- get_top_activity:获取当前 Activity
- get_top_activity_name_and_pid:获取当前 Activity 的名称和进程号
- get_top_activity_name:获取当前 Activity 的名称
- is_keyboard_shown:判断当前键盘是否出现了
- is_locked:设备是否锁定了
- unlock:解锁设备
- display_info:获取当前显示信息,如屏幕宽高等
- get_display_info:同 display_info
- get_current_resolution:获取当前设备分辨率
- get_render_resolution:获取当前渲染分辨率
- start_recording:开始录制
- stop_recording:结束录制
- adjust_all_screen:调整屏幕适配分辨率
了解了上面的方法之后,我们可以用一个实例来感受下它们的用法:
1 |
from airtest.core.android import Android |
这里我们调用了设备的一些操作方法,获取了一些基本状态,运行结果如下:
1 |
is_locked: False |
连接 device
连接 device 需要传入设备的 uri,格式类似 android://adbhost:adbport/serialno?param=value¶m2=value2
,使用方法如下:
1 |
def connect_device(uri): |
示例如下:
1 |
from airtest.core.android import Android |
运行结果如下:
1 |
<airtest.core.android.android.Android object at 0x110246940> |
其实返回结果和 init_device 是一样的,最后 connect_device 方法就是调用了 init_device 方法。
获取当前 device
就是直接调用 device 方法,定义如下:
1 |
def device(): |
获取所有 device
在 airtest 中有一个全局变量 G,获取所有 device 的方法如下:
1 |
from airtest.core.android import Android |
运行结果如下:
1 |
[] |
这里需要注意的是,在最开始没有调用 connect_device 方法之前,DEVICE_LIST 是空的,在调用之后 DEVICE_LIST 会自动添加已经连接的 device,DEVICE_LIST 就是已经连接的 device 列表
切换 device
我们可以使用 set_current 方法切换当前连接的 device,传入的是 index,定义如下:
1 |
def set_current(idx): |
这个方法没有返回值,调用 set_current 方法切换 device 之后,再调用 device 方法就可以获取当前 device 对象了。
执行命令行
可以使用 shell 方法传入 cmd 来执行命令行,定义如下:
1 |
@logwrap |
直接调用 adb 命令就好了,例如获取内存信息就可以使用如下命令:
1 |
from airtest.core.api import * |
运行结果如下:
1 |
MemTotal: 3627908 kB |
启动和停止 App
启动和停止 App 直接传入包名即可,其实它们就是调用的 device 的 start_app 和 stop_app 方法,定义如下:
1 |
@logwrap |
用法示例如下:
1 |
from airtest.core.api import * |
这里我指定了微信的包名,然后调用 start_app 启动了微信,然后等待了 10 秒,然后调用了 stop_app 停止了微信。
安装和卸载
安装和卸载也是一样,也是调用了 device 的 install 和 uninstall 方法,定义如下:
1 |
@logwrap |
截图
截图使用 snapshot 即可完成,可以设定存储的文件名称,图片质量等。 定义如下:
1 |
def snapshot(filename=None, msg="", quality=ST.SNAPSHOT_QUALITY): |
示例如下:
1 |
from airtest.core.api import * |
运行之后在当前目录会生成一个 weixin.png 的图片,如图所示:
唤醒和首页
唤醒和回到首页分别也是调用了 device 的 wake 和 home 方法,定义如下:
1 |
|
直接调用即可。
点击屏幕
点击屏幕是 touch 方法,可以传入一张图或者绝对位置,同时可以指定点击次数,定义如下:
1 |
@logwrap |
例如我现在的手机屏幕是这样子: 这里我截图下来一张图片,如图所示: 然后我们把这个图片声明成一个 Template 传入,示例如下:
1 |
from airtest.core.api import * |
启动之后它就会识别出这张图片的位置,然后点击。 或者我们可以指定点击的绝对位置,示例如下:
1 |
from airtest.core.api import * |
另外上述的 touch 方法还可以完全等同于 click 方法。 如果要双击的话,还可以使用调用 double_click 方法,传入参数也可以是 Template 或者绝对位置。
滑动
滑动可以使用 swipe 方法,可以传入起始和终止位置,两个位置都可以传入绝对位置或者 Template,定义如下:
1 |
@logwrap |
比如这里我们可以定义手指向右滑动:
1 |
from airtest.core.api import * |
放大缩小
放大缩小是使用的 pinch 方法,可以指定放大还是缩小,同时还可以指定中心位置点和放大缩小的比率。 定义如下:
1 |
@logwrap |
示例如下:
1 |
from airtest.core.api import * |
键盘事件
可以使用 keyevent 来输入某个键,例如 home、back 等等,keyevent 的定义如下:
1 |
def keyevent(keyname, **kwargs): |
示例如下:
1 |
keyevent("HOME") |
这样就表示按了 HOME 键。
输入内容
输入内容需要使用 text 方法,当然前提是这个 widget 需要是 active 状态,text 的定义如下:
1 |
@logwrap |
等待和判断
可以使用 wait 方法等待某个内容加载出来,需要传入的是 Template,定义如下:
1 |
@logwrap |
同时也使用 exists 方法判断某个内容是否存在,定义如下:
1 |
|
断言
另外 Airtest 还提供了几个断言语句来判断结果是否存在或者相同,定义如下:
1 |
@logwrap |
这几个断言比较常用的就是 assert_exists 和 assert_not_exists 判断某个目标是否存在于屏幕上,同时还可以传入 msg,它可以被记录到 report 里面。 以上就是 Airtest 的 API 的用法,它提供了一些便捷的方法封装,同时还对接了图像识别等技术。 但 Airtest 也有一定的局限性,比如不能根据 DOM 树来选择对应的节点,依靠图像识别也有一定的不精确之处,所以还需要另外一个库 —— Poco。
Poco
利用 Poco 我们可以支持 DOM 选择,例如编写 XPath 等来定位某一个节点。 首先需要安装 Poco,使用 pip3 即可:
1 |
pip3 install pocoui |
安装好了之后我们便可以使用它来选择一些节点了,示例如下:
1 |
from airtest.core.api import * |
比如这里我们就声明了 AndroidUiautomationPoco 这个 Poco 对象,然后调用了 poco 传入一些选择器,选中之后执行 click 方法。 这个选择器非常强大,可以传入 name 和各个属性值,具体的使用方法见:https://poco.readthedocs.io/en/latest/source/poco.pocofw.html
1 |
from airtest.core.api import * |
poco 返回的是 UIObjectProxy 对象,它提供了其他的操作 API,例如选取子节点,兄弟节点,父节点等等,同时可以调用各个操作方法,如 click、pinch、scroll 等等。 具体的操作文档可以参见:https://poco.readthedocs.io/en/latest/source/poco.proxy.html 下面简单总结:
- attr:获取节点属性
- child:获取子节点
- children:获取所有子节点
- click:点击
- double_click:双击
- drag_to:将某个节点拖拽到另一个节点
- exists:某个节点是否存在
- focus:获得焦点
- get_bounds:获取边界
- get_name:获取节点名
- get_position:获取节点位置
- get_size:获取节点大小
- get_text:获取文本内容
- long_click:长按
- offspring:选出包含直接子代的后代
- parent:父节点
- pinch:缩放
- scroll:滑动
- set_text:设置文字
- sibling:兄弟节点
- swipe:滑动
- wait:等待
- wait_for_appearance:等待某个节点出现
- wait_for_disappearance:等待某个节点消失
以上的这些方法混用的话就可以执行各种节点的选择和相应的操作。