目录
1、UIautomator2框架原理
2、UIautomator2使用
2.1、安装
2.2、元素定位工具-weditor
2.3、设备连接
2.4、全局配置
2.4.1、通过settings设置
2.4.2、通过属性设置
2.5、APP相关操作
2.5.1、安装应用
2.5.2、启动应用
2.5.3、等待应用启动
2.5.4、结束应用
2.5.5、卸载应用
2.5.6、获取当前上层APP的信息
2.5.7、获取指定APP的信息
2.6、设备相关操作
2.6.1、获取设备信息
2.6.2、 获取屏幕分辨率
2.6.3、获取设备IP地址
2.6.4、锁屏亮屏
2.6.5、截屏
2.6.6、按键
2.6.7、输入法切换
2.6.8、录屏
2.6.9、文件的上传下载
2.8、元素定位
2.8.1、定位方法
2.8.2、支持的定位方法
2.8.3、 组合定位
2.8.4、子元素定位
2.8.5、兄弟元素定位
2.8.6、多级定位
2.8.9、相对定位
2.8.10、xpath定位
2.9、元素操作
2.9.1、点击
2.9.2、长按
2.9.3、滑动
2.9.4、多点滑动
2.9.5、拖动
2.9.6、放大缩小
2.9.7、滚动
2.9.8、toast操作
2.9.9、文本相关操作
2.9.10、弹窗监测
如上图所示,python-uiautomator2 主要分为两个部分,python 客户端,移动设备
完整流程
pip3 install -U uiautomator2
python3 -m uiautomator2 init
uiautomator2 verison
import uiautomator2 as u2
d = u2.connect() # 连接设备
print(d.info)
1、安装:
pip install weditor==0.6.4
2、启动weditor
python -m weditor
3、连接Android设备
1、默认一个设备的情况
import uiautomator2 as u2
# 连接设备
d = u2.connect()
# 当PC与设备在同一网段时,可以使用IP地址和端口号通过WIFI连接,无需连接USB线
# 默认使用端口号7912
u2.connect("10.0.0.1:7912")
u2.connect("10.0.0.1")
u2.connect("http://10.0.0.1")
u2.connect("http://10.0.0.1:7912")
等价于
u2.connect_wifi("10.0.0.1:7912")
2、多个设备时指定设备连接
import uiautomator2 as u2
# 连接设备,xxx:表示指定设备的设备号,可使用命令adb devices查看
d = u2.connect("xxx")
等价于
d = u2.connect_usb("xxx")
1、查看settings默认设置
print(d.settings)
# 默认配置如下:
{
# 截屏失败时返回空白截屏(不抛出异常)
'fallback_to_blank_screenshot': False,
# 操作延迟,(0, 0)表示元素点击前等待0秒,点击后等待0S再执行后续操作
'operation_delay': (0, 0),
# opretion_delay生效的方法,默认为click和swipe
# 还可以设置press,send_keys,long_click等方式
'operation_delay_methods': ['click', 'swipe'],
# 元素默认等待时间(隐式等待)
'wait_timeout': 20.0,
# xpath日志
'xpath_debug': False
}
2、通过settIng修改默认配置
# 修改截图失败后的默认返回
d.settings["fallback_to_blank_screenshot"] = True
# 修改操作延迟时间
d.settings["operation_delay"] = (3, 3)
# 修改操作延迟方法
d.settings["operation_delay_methods"] = ['click', 'swipe', 'press']
# 修改默认等待时间
d.settings["wait_timeout"] = 10
# 查看是否修改成功
print(d.settings)
1、http默认请求超时时间
# 默认值60s
d.HTTP_TIMEOUT = 60
2、等待设备在线时长
# 默认20s
d.WAIT_FOR_DEVICE_TIMEOUT = 60
3、HTTP debug信息
d.debug = True
# 本地路径安装
d.app_install('tmp.apk')
# url安装
d.app_install('package_url')
# 如果已启动且在后台会被拉起到前台
# 如果已启动且在前台,不做任何操作,结束
# 如果未启动,则冷启动该应用
d.app_start("packageName")
# 先kill掉APP,再冷启动APP
d.app_start("packageName", stop=True)
# 等待此应用变为当前上层应用,返回pid,超时未启动成功则返回0
# front默认为false表示只要该应用在运行中就会返回pid 为true表示等待app成为当前app
d.app_wait('com.xxx', 30, front=True)
# 通过包名结束单个应用
d.app_stop("packageName") # 强制结束应用,但是不清除应用数据
d.app_clear('packageName') # 结束应用,并且清除应用数据
# 默认结束所有第三方应用,保留uiautomator两个依赖服务应用
# excludes参数:排除列表中的应用包名
d.app_stop_all(excludes=['com.xxx.xxx'])
# 卸载成功返回true,没有此包或者卸载失败返回False
d.app_uninstall('com.xxx.xxx')
d.app_current()
d.app_info("com.XXX")
# 输出设备的详细信息,报告设备号,电池,CPU信息等
d.device_info
# 手机竖屏状态返回 (1080,2400)
# 横屏状态返回 (2400,1080)
d.window_size()
d.wlan_ip
# 锁屏
d.screen_off()
# 亮屏
d.screen_on()
# 截图,save(fp) 传文件路径地址
d.screenshot().save("./tmp.png")
from PIL import Image
# 旋转90度截屏(逆时针旋转)
d.screenshot().transpose(Image.ROTATE_90).save("./tmp2.png")
# 按音量键"+"
d.press('volume_up')
"""
press key via name or key code. Supported key name includes:
home, back, left, right, up, down, center, menu, search, enter,
delete(or del), recent(recent apps), volume_up, volume_down,
volume_mute, camera, power.
"""
# 切换成uiautomator2的输入法,这里会隐藏掉系统原本的输入法,默认是使用系统输入法
# 当传入False时会使用系统默认输入法,默认为Fasle
d.set_fastinput_ime(True)
# 查看当前输入法
d.current_ime()
pip3 install -U "uiautomator2[image]" -i https://pypi.doubanio.com/simple
# 启动录制,默认帧率为20
d.screenrecord('tmp.mp4')
# 执行其它操作
time.sleep(10)
# 停止录制,录制结束后生成视频
d.screenrecord.stop()
# 上传文件(从电脑推送到手机) 如果是目录,这里"/sdcrad/"最后一个斜杠一定要加,否则会报错
d.push("test.txt","/sdcrad/")
d.push("test.txt","/sdcrad/test.txt")
# 下载文件(从手机推送到电脑)
d.pull('/sdcard/test.txt','text.txt')
2.7、等待
说明:等待分为强制等待和隐式等待;
# 设置强制等待的时间为3秒,等价于:time.sleep(3)
d.sleep(3)
# 设置隐式等待的时间为10
d.implicitly_wait(10)
d(定位方法=定位方法的值)
# 示例
#返回一个列表,当没找到元素时,返回一个空列表;存在多个元素时,返回多个列表元素
elements = d(text='Setting')
elements[0].click()
#获取元素个数
print(elements.count)
定位方法 |
描述 |
text |
text是指定文本的元素 |
textContains |
text中包含有指定文本的元素 |
textMatches |
text符合指定正则的元素 |
textStartsWith |
text以指定文本开头的元素 |
className |
className是指定类名的元素 |
classNameMatches |
className类名符合指定正则的元素 |
description |
description是指定文本的元素 |
descriptionContains |
description中包含有指定文本的元素 |
descriptionMatches |
description符合指定正则的元素 |
descriptionStartsWith |
description以指定文本开头的元素 |
checkable |
可检查的元素,参数为True,False |
checked |
已选中的元素,通常用于复选框,参数为True,False |
clickable |
可点击的元素,参数为True,False |
longClickable |
可长按的元素,参数为True,False |
scrollable |
可滚动的元素,参数为True,False |
enabled |
已激活的元素,参数为True,False |
focusable |
可聚焦的元素,参数为True,False |
focused |
获得了焦点的元素,参数为True,False |
selected |
当前选中的元素,参数为True,False |
packageName |
packageName为指定包名的元素 |
packageNameMatches |
packageName为符合正则的元素 |
resourceId |
resourceId为指定内容的元素 |
resourceIdMatches |
resourceId为符合指定正则的元素 |
d(className="xxx", text="xxx")
d(className="xxx").child(text="xxx")
d(text="xxx").sibling(className="android.widget.TextView")
d(className="xxx", resourceId="xxx").child_by_text("xxx").child(className="xxxx")
d(A).left(B),# 选择A左边的B
d(A).right(B),# 选择A右边的B
d(A).up(B), #选择A上边的B
d(A).down(B),# 选择A下边的B
# 示例
d(text='xxx').right(className="android.widget.TextView")
# 如果找不到元素,则会报XPathElementNotFoundError错误
# 如果找到多个元素,默认返回第1个
d.xpath('//*[@content-desc="xxx"]')
# 如果想要返回的元素有多个,使用all()方法返回列表
# 使用all方法,当未找到元素时,不会报错,会返回一个空列表
d.xpath('//*[@resource-id="xxx"]').all()
d(text='xxx').click()
#单击直到元素消失,超时时间5,点击间隔1
d(text='xxx').click_gone(maxretry=5, interval=1.0)
d(text='xxx').long_click()
# 根据坐标滑动从(x1,y1)滑动到(x2,y2)
d.swipe(x1,y1,x1,y2)
# 滑动的扩展方法,支持上下左右的滑动
# "left", "right", "up", "down"
d.swipe_ext("up")
# 按下不放手
touch.down(x,y)
# 停住1S
touch.sleep(1)
# 移动
touch.move(x,y)
# 放开
touch.up(x,y)
#实现长按,同一个点按下休眠10S后抬起
d.touch.down(x1,y1).sleep(10).up(x1,y1)
# 实现多点之间的移动
d.touch.down(x1,y1).move(x2,y2).move(x3,y3).up(x3,y3)
# 在0.5s内将设置拖动至QQ上,拖动元素的中心位置
# duration默认为0.5,实际拖动的时间会比设置的要高
d(description="设置").drag_to(text="QQ", duration=0.5)
# 拖动设置到屏幕的(500, 500)位置上
d(text="设置").drag_to(500,500, duration=0.5)
# 从点(x1,y1)拖动到点(x2,y2)
d.drag(x1,y1,x2,y2)
# 根据坐标进行放大和缩小
d(className="android.widget.FrameLayout").gesture(start1,start2,end1,end2)
# 缩小
d(className="android.widget.FrameLayout").pinch_in(50, 50)
# 放大
d(className="android.widget.FrameLayout").pinch_out(10, 10)
# 垂直滚动到页面顶部/横向滚动到最左侧
d(scrollable=True).scroll.toBeginning()
d(scrollable=True).scroll.horiz.toBeginning()
# 垂直滚动到页面最底部/横向滚动到最右侧
d(scrollable=True).scroll.toEnd()
d(scrollable=True).scroll.horiz.toEnd()
# 垂直向后滚动到指定位置/横向向右滚动到指定位置
d(scrollable=True).scroll.to(text="指定位置")
d(scrollable=True).scroll.horiz.to(text="指定位置")
# 垂直向前滚动(横向同理)
d(scrollable=True).scroll.forward()
# 垂直向前滚动到指定位置(横向同理)
d(scrollable=True).scroll.forward.to(text="指定位置")
# 获取toast,当没有找到toast消息时,返回default内容
d.toast.get_message(timout=3, default='no toast')
# 清空toast缓存
d.toast.reset()
# 获取元素文本
d(text="xxx").get_text()
# 设置元素文本
d(text="xxx").set_text()
# 清除元素文本
d(text="xxx").clear_text()
# 注册监控,当页面内出现有OK时,点击OK
d.watcher.when('OK').click()
# 移除 allow 的监控
d.watcher.remove("allow")
# 移除所有的监控
d.watcher.remove()
# 开始后台监控
d.watcher.start()
d.watcher.start(2.0) # 默认监控间隔2.0s
# 强制运行所有监控
d.watcher.run()
# 停止监控
d.watcher.stop()
# 停止并移除所有的监控,常用于初始化
d.watcher.reset()