一、简介
安装
pip install pocoui
# 安装这个pocoui会自动安装airtest库
airtest和poco的区别
airtest是基于图像识别来锁定位置的,
而poco是基于画面的UI控件层次的关系来确定控件位置的。
二、airtest
初始化
# 连接有线的手机
from airtest.core.api import *
from airtest.cli.parser import cli_setup
if not cli_setup():
auto_setup(__file__, logdir=None, devices=["android://",])
# 无线连接
from airtest.core.api import *
from airtest.cli.parser import cli_setup
if not cli_setup():
auto_setup(__file__, logdir=None, devices=["android://127.0.0.1:5037/192.168.0.100:5555",])
'''
127.0.0.1:5037是adb进程端口,不用管
192.168.0.100:5555是手机的ip,5555是想占用的端口
'''
PS:android:///127.0.0.1:5037/192.168.0.100:5555
是错误写法,多了一个/
,它的内部实现connect_device()
就解析不出来
日志等级
import logging
logger = logging.getLogger("airtest")
logger.setLevel(logging.ERROR)
基本
# 点击
touch((100, 100))
# 识图点击
touch(Template(r"tpl1622173970599.png", record_pos=(0.003, 0.106), resolution=(1080, 1920)))
# 判断图像存在:存在返回点击位置,不存在返回False
result = exists(Template(r"tpl1622169735958.png", record_pos=(0.224, -0.245), resolution=(1080, 1920)))
if result is not False:
print(result)
# 休眠3秒
sleep(3.0)
# 输入
text("我爱你")
按键
三、Poco
https://www.cnblogs.com/wutaotaosin/articles/11398679.html
初始化
# 连接Android设备
同上Airtest
# 初始化用于Android的poco
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
选择控件
传入控件的
name
如果不重名的话,百分百就是你想要的控件。重名的话,那么获得的是多个控件的列表,但你要是直接item.click()
操作的话,默认选择列表的第一个。
item = poco("com.android.systemui:id/scrim_behind")
根据文字内容找
item = poco(text='书架')
根据层次定位
# parent()是父节点,child()是直接的孩子,offspring孩子和子孙都是
# 里面就像poco()一样,可以不指定name都选择,也可以选择指定name的控件。
items = poco('main_node').parent().child('list_item').offspring('item')
# 多个结果是列表
item_2 = items[1]
# 可以迭代
for item in items:
print(item)
item.click()
PS:因为Poco是动态渲染的UI,所以列表内元素的排序可能会发生变化,从而出现上次还能运行,这次就找不到控件的现象。
# 也许这次,android.widget.LinearLayout>android.view.View/[2],"android.widget.LinearLayout>android.view.View/[3]/"
items = poco("android.widget.LinearLayout").offspring("android.view.View")
for i in items:
print(i)
'''
UIObjectProxy of "android.widget.LinearLayout>android.view.View/[2]/"
UIObjectProxy of "android.widget.LinearLayout>android.view.View/[3]/"
UIObjectProxy of "android.widget.LinearLayout>android.view.View/[0]/"
UIObjectProxy of "android.widget.LinearLayout>android.view.View/[1]/"
'''
有条件限制的解决办法:虽然这个控件的名字有重复的,但如果这个控件的上层控件是可以唯一确定,那么就可以先锁定到这个上层控件,再索引到这个子控件的名字。
item = poco(text="时区1").offspring("android.view.View")
判断控件是否存在
exists = item.exists()
print(exists)
# True/False, exists in the screen or not
实战:
# 查的时候如果没有不会报错
items = poco('main_node').child('list_item').offspring('item')
# 用的时候如果没有会报错PocoNoSuchNodeException
# items.click()
if items.exists():
items.click()
pass
# 如果没有会报下标IndexError的错,这个防不住
item_1 = items[0] # 在这里就报错了,下面没用
# if item_1.exists():
# pass
获取控件属性
item = poco("android.view.ViewGroup").child("android.widget.RelativeLayout")[14].child("com.bbk.launcher2:id/item_title")
print(item.attr('type'))
print(item.attr('name'))
print(item.attr('text'))
print(item.attr('pos'))
'''
android.widget.TextView
com.bbk.launcher2:id/item_title
哔哩哔哩
[0.3814814814814815, 0.7958333333333333]
'''
点击
# 控件.click()
item.click()
# 即[0.5, 0.5]
item.click('center')
# 右x下y坐标系,左上角为原点[0, 0],右下角为[1, 1]。
item.click([1.0, 1.0])
滑动
滑动控件
# 局部坐标系:以UI包围盒左上角为原点,向右为x轴,向下为y轴,包围盒宽和高均为单位一。
item.swipe('up')
item.swipe([0.2, -0.2]) # swipe sqrt(0.08) unit distance at 45 degree angle up-and-right
item.swipe([0.2, -0.2], duration=0.5)
滑动屏幕
# 归一化坐标系:整张屏幕的尺度
# 从屏幕右下角,滑动到屏幕中间
point_a = [1, 1]
center = [0.5, 0.5]
poco.swipe(point_a, center)
拖拽
# 把一个UI控件拖到另一个UI控件
item_1.drag_to(item_2)
# 拖到屏幕的位置
item_1.drag_to([0.2361111111111111, 0.834375])
等待出现
item.wait(5).click() # wait 5 seconds at most,click once the object appears
item.wait(5).exists() # wait 5 seconds at most,return Exists or Not Exists
截图
from base64 import b64decode
b64img, fmt = poco.snapshot(width=720)
with open('screen.{}'.format(fmt), 'wb') as f:
f.write(b64decode(b64img))