之前介绍了Airtest 基于图像识别的方法,这也是最简单、最方便的操作,能满足大部分的使用场景;当然除了这种"傻瓜式"的操作,Airtest 还带有一种基于UI控件的操作,跟Appium的定位方式差不多,作为一种补充,大家可以根据实际需要使用。这部分内容主要介绍两部分:Poco Instance API、UI proxy object API。
Poco Instance API
一般在Poco 辅助窗口选择好引擎之后,会自动生成初始代码,我这里以Android为例,生成一个 Poco实例之后,就可以使用该类的所有方法。
scroll(direction=‘vertical’,percent=0.6,duration=2.0):滚动屏幕,从下部滚动到上部;常见参数如下:
direction | 滚动方向,vertical / horizontal; |
---|---|
percent | 滚动距离占整个屏幕高度或宽度的百分比; |
duration | 操作执行的时间间隔; |
get_screen_size():获取目标设备屏幕的真实物理分辨率,返回一个元素类型;
size = poco.get_screen_size() # [1080, 2220]
click(pos):点击;
pos | 点击坐标,百分比形式,在0~1之间,(x,y) 或[x,y]; |
---|
freeze():将当前层次结构生成一个快照,缓存到一个新的poco实例中,这个新的poco实例是当前poco实例的副本,新的poco实例层次结构是固定不可变的;
将当前层次结构生成一个快照,缓存到一个新的poco实例中,这个新的poco实例是当前poco实例的副本,新的poco实例层次结构是固定不可变的;
long_click(pos,duration=2.0):长按屏幕;
pos | 点击坐标,百分比形式,在0~1之间,(x,y) 或[x,y]; |
---|---|
duration | 操作执行的时间间隔; |
pinch(direction=‘in’,percent=0.6,duration=2.0,dead_zone=0.1):缩小/放大屏幕;参数如下:
direction | in-缩小,out-放大; |
---|---|
percent | 缩小/放大百分比; |
duration | 操作执行的时间; |
dead_zone | 操作半径不能大于percent |
snapshot(width=720):截图;
width | 预期宽度,以实际为准; |
---|
swipe(p1,p2=None,direction=None,duration=2.0):滑动屏幕;在这里要注意一下,滑动完成之后最好加一个等待时间,再进行下一步操作,否则页面还没刷出来就去操作,直接报错,我在不同的地方遇到过多次。注意:在UI层次结构里面有 pos 的坐标信息,不要直接使用,因为不同手机,这个值不一样,需要换算。
p1 | 起点,(x,y)或[x,y]; |
---|---|
p2 | 终点; |
direction | 滑动方向; |
duration | 滑动时间; |
poco.swipe((0.5,0.5797), (0.5,0.1180), duration=0.5)
wait_for_all(object,timeout=120):等待,直到所有给定的UI代理在超时之前出现。
object | UI代理的可迭代对象; |
---|---|
timeout | 超时时间,默认120秒; |
UI proxy object API
UI Proxy 类,表示目标设备上的UI元素,在此实例上执行的任何操作都有 Poco处理,不需要手动初始化对象。这里我们先介绍几种与UI 元素查找相关的属性以及查找方法,然后再介绍操作方法。
常见属性:
visible | 是否对用户可见; |
---|---|
text | UI元素的值; |
type | UI元素类型; |
name | UI 元素名称; |
resourceId | UI元素id; |
pos | UI元素位置;不同设备不固定,较少使用; |
size | UI元素尺寸,百分比;不同设备尺寸不同,较少使用; |
menu = poco(resourceId='com.tencent.mm:id/uv')
menu[4].click()
poco(text="请输入手机号").set_text(mobile)
poco(text="登录/注册",name="android.widget.Button").click()
除了利用属性进行元素定位,还可以利用正则表达式
textMatches | 匹配文本正则; |
---|---|
nameMatches | 匹配 UI 元素的 name 属性; |
typeMatches | UI 元素类型匹配; |
xxMatches | 其他属性匹配; |
poco(textMatches='^close.*$')
poco(textMatches=".*海博君亿.*").sibling(name="android.widget.Image").click()
poco(resourceIdMatches='.*MQ2127$).click()
元素层级定位方法:
child(name=None,**attrs):返回当前元素的子元素(子节点);有多个子节点,默认取第一个;
name | 查询带有name属性的子元素; |
---|---|
attrs | 其它属性; |
poco(name="com.tencent.mm:id/t5").child().child(name="com.tencent.mm:id/uu")[4].click()
## 只有一个子元素,可以不用指定子元素属性
poco(name="com.tencent.mm:id/t5").child(name="android.widget.LinearLayout").child(name="com.tencent.mm:id/uu")[4].click()
children():与 child() 相似,但它是从UI元素中选择所有子节点;
offspring(name=None,**attrs):返回当前元素包括直接子元素在内的孙节点;返回一个新的 UI Proxy 对象,表示当前 UI 元素的子元素,通过索引操作指定的元素;如下图例子:
menu = poco(name="com.tencent.mm:id/t5").offspring(name="com.tencent.mm:id/uu")
menu[4].click()
parent():返回当前节点的父节点,返回一个新的 UI Proxy 对象,表示第一个 UI 元素的直接父元素;
sibling(name=None,**attrs):选择同级元素(兄弟节点);
相关操作:
click(focus=None,sleep_interval=None):点击元素,如果是一组元素,点击第一个;参数如下:
focus | 点击坐标,百分比形式,在0~1之间,(x,y) 或 [x,y]; |
---|---|
sleep_interval | 操作后的等待秒数,默认是 None; |
double_click(focus=None,sleep_interval=None):双击,如果元素是一组,点击第一个;参数同上;
drag_to(target,duration=2.0):拖动;
target | 拖动目的地,一个UI代理或坐标; |
---|---|
duration | 操作执行时间; |
exists():判断元素是否存在;这个很常用,用于判断是否下一步操作;
focus(f):获取具有给定焦点的新UI代理副本,返回要给新的 UI 代理对象;
f | 点击坐标,百分比形式,在0~1之间,(x,y) 或 [x,y]; |
---|
get_bounds():获取 UI元素的边界框参数;返回 4 个list(上、右、下、左);
get_name():获取 UI元素名称属性;
get_position(focus=None):获取 UI元素位置;返回一个 (x,y);
get_size():获取 UI 元素大小;返回一个 [width,height],在 0~1 之间;
get_text():获取 UI 元素的text属性;
invalidate():清除标志,表示从层次结构中重新查询或重新选择 UI 元素,别名是 refresh();
a = poco(text="settings")
print(a.exists())
a.refresh()
print(a.exists())
long_click(duration=2.0):长点击,如果是一组元素,点击第一个;
duration | 整个动作持续时间; |
---|
pinch(direction=‘in’, percent=0.6, duration=2.0, dead_zone=0.1):缩小/放大;参数如下:
direction | in-缩小,out-放大; |
---|---|
percent | 缩小/放大百分比; |
duration | 操作执行时间; |
dead_zone | 缩小/放大的半径,不大于percent; |
rclick(focus=None,sleep_interval=None):在元素上执行右键操作,如果是一组元素,点击第一个;参数参考 click();
refresh():刷新 UI,重新选择;
scroll(direction=‘vertical’,percent=0.6,duration=2.0):滚动;
direction | 滚动方向,vertical / horizontal; |
---|---|
percent | 滚动距离占整个屏幕高度或宽度的百分比; |
duration | 操作执行时间; |
set_text(text):设置 UI 元素的 text属性值;注意:如果无法输入,尝试使用 Airtest 的 text 接口;set_text(" ") 删除操作;
poco(text="请输入手机号").set_text("131209116xx")
setattr(name,val):设置 UI 元素属性值;
name | 属性名称; |
---|---|
val | 新的属性值; |
swipe(direction,focus=None,duration=0.5):滑动;
direction | 滑动方向,向上滑动相当于[0,-0.1],向下滑动相当于[0,0.1],向左滑动相当于[-0.1,0],向右滑动相当于[0.1,0] |
---|---|
focus | 百分比形式,在0~1之间,(x,y) |
duration | 操作执行时间; |
wait(timeout=3):阻塞并等待 UI 元素出现之前的最大等待时间;
wait_for_appearance(timeout=120):阻塞并等待,直到 UI 元素在给定的超时内消失;
最后强调一下,选择Android 引擎时,会自动生成2行代码,包括了一个Poco对象,这里使用的是默认的设备,但是,也可以指定设备,就是使用 connect_device(“Android://127.0.0.1:5037/serial_id”),然后将整个设备传入 AndroidUiautomationPoco()类中;
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
# 链接指定设备
dev = connect_device("Android://127.0.0.1:5037/serial")
poco = AndroidUiautomationPoco(dev)
如果有多台Android设备,需要分开进行初始化;
from airtest.core.api import *
auto_setup(__file__,devices=["android://127.0.0.1:5037/127.0.0.1:7555","android://127.0.0.1:5037/0123456789"])
from airtest.core.android import Android
dev1 = Android('127.0.0.1:7555')
dev2 = Android('0123456789')
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco1 = AndroidUiautomationPoco(dev1)
poco2 = AndroidUiautomationPoco(dev2)
poco1(text="网易云音乐").click()
poco2(text="网易云音乐").click()
这篇内容比较多,可以先收藏了慢慢看,里面有些提示点,都是自己踩过的坑,内容有不足之处,还请批评指正!也欢迎大家多多交流!
最后多说一句,结合前面的内容,在工作中基本够用,如果还有更多的需求,可以参考官方文档!