一、环境安装
pip3 install -U uiautomator2
pip3 install -U weditor
命令行输入:weditor 即可打开UI结构树界面
网址:https://github.com/openatx/uiautomator2
二、命令行 uiautomator2
查看命令帮助:uiautomator2 --help
- 截图:uiautomator2 screenshot 123.jpg
- 获取当前的包名和activity:uiautomator2 current
三、API命令
1、设置元素查找等待时间
- 设置:
d.implicitly_wait(10.0)
d.settings[‘wait_timeout’] = 10.0 - 查看: print(“wait timeout”, d.implicitly_wait())
2、启动APP
- 如果启动失败:可以考虑加上
use_monkey=True
3、 文件上传下载
-
推送文件
# 推送到文件夹 d.push("foo.txt", "/sdcard/") # 推送并重名 d.push("foo.txt", "/sdcard/bar.txt") # 推送文件对象 with open("foo.txt", 'rb') as f: d.push(f, "/sdcard/") # 推送文件,并且修改权限 d.push("foo.sh", "/data/local/tmp/", mode=0o755)
4、打开web浏览器
d.open_url("https://www.baidu.com")
5、手机终端运行Linux命令
-
简单使用
# 默认超时60s output, exit_code = d.shell("pwd", timeout=60) output = d.shell("pwd").output exit_code = d.shell("pwd").exit_code
output, exit_code = d.shell(["ls", "-l"])
-
长时间运行
r = d.shell("logcat", stream=True) deadline = time.time() + 10 # 打印10s try: for line in r.iter_lines(): # r.iter_lines(chunk_size=512, decode_unicode=None, delimiter=None) if time.time() > deadline: break print("Read:", line.decode('utf-8')) finally: r.close()
6、会话
sess = d.session("com.netease.cloudmusic") # start 网易云音乐
sess.close() # 停止网易云音乐
sess.restart() # 冷启动网易云音乐
sess(text="Music").click()
7、按键事件
-
关闭开启屏幕
d.screen_on() d.screen_off() d.info.get('screenOn')
-
按键
d.press("home") d.press("back")
-
解锁屏幕
d.unlock()
-
鼠标事件
d.click(x, y) d.double_click(x, y, 0.1) d.long_click(x, y, 0.5) d.swipe(sx, sy, ex, ey, 0.5) # sx,sy 滑动到 ex,ey d.swipe_ext("right") # 手指右滑,4选1 "left", "right", "up", "down" d.swipe_ext("right", scale=0.9) # 默认0.9, 滑动距离为屏幕宽度的90% d.swipe_ext("right", box=(0, 0, 100, 100)) # 在 (0,0) -> (100, 100) 这个区域做滑动 d.swipe_points([(x0, y0), (x1, y1), (x2, y2)], 0.2)) # 解锁九宫格 # 拖动 d.drag(sx, sy, ex, ey) d.drag(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default) 以上均支持百分比操作:如d.long_click(0.5, 0.5) 代表点击中间位置
-
输入
d.set_fastinput_ime(True) # 切换成FastInputIME输入法 d.send_keys("你好123abcEFG") # adb广播输入 d.clear_text() # 清除输入框所有内容 d.set_fastinput_ime(False) # 切换成正常的输入法
8、简单选择器(自带方式)
-
文本(text)
d(text="显示").click() # 精确匹配 d(textContains="显示").get_text() # 包含 d(textMatches="^显示$") # 正则 以显为开头,示为结束 d(textStartsWith="显示") # 以什么开头
-
类名( className android.widget.LinearLayout)
d(className="android.widget.TextView",instance=0).get_text() # 使用第一个符合类的属性 d(classNameMatches=".+TextView$",instance=0).get_text() # 正则匹配
-
描述(description )
description, descriptionContains, descriptionMatches, descriptionStartsWith
-
ID( resourceId )
resourceId, resourceIdMatches
-
多个相同的元素
使用属性:instance指定哪一个 d(textContains="显示",instance=0).get_text() # 指定第一个 d(textContains="显示")[0] # 指定第一个 for i in d(textContains="显示"): print(i.text)
9、关系选择器
-
后代选择
d(className="android.widget.LinearLayout").child(text="网络和互联网").click() d(className="android.widget.LinearLayout").child(resourceId="android:id/widget_frame").child(resourceId="com.android.settings:id/switchWidget").click()
-
兄弟选择
# 所有的兄弟姐妹,包含自己 d(text="网络和互联网").sibling(className="android.widget.TextView")
10、元素
-
元素判断
d(text="Settings").exists d(text="Settings").exists(timeout=3) d(text="WLAN").wait(timeout=3) # 存在则返回 True # 不存在返回 False
-
文本操作
d(text="Settings").get_text() # get widget text d(text="Settings").set_text("My text...") # set the text d(text="Settings").clear_text() # clear the text
-
点击
d(text="Settings").click() d(text="Settings").click(timeout=10) d(text='Settings').click_exists(timeout=10.0) d(text="Settings").click_gone(maxretry=10, interval=1.0) # 每隔1s 最多点击10次,等待元素不见返回bool d(text="Settings").long_click(duration=2) # 长点击多长时间释放
-
等待元素消失
d(text="Settings").wait(timeout=3.0) # return bool 等待3S出现 d(text="Settings").wait_gone(timeout=1.0) # 等待1S消失
11、监控
-
注册监控
# 常用写法,注册匿名监控 d.watcher.when("安装").click() # 注册名为ANR的监控,当出现ANR和Force Close时,点击Force Close d.watcher("ANR").when(xpath="ANR").when("Force Close").click() # 其他回调例子 d.watcher.when("抢红包").press("back") d.watcher.when("//*[@text = 'Out of memory']").call(lambda d: d.shell('am force-stop com.im.qq')) # 回调说明 def click_callback(d: u2.Device): d.xpath("确定").click() # 在回调中调用不会再次触发watcher d.xpath("继续").click() # 使用d.xpath检查元素的时候,会触发watcher(目前最多触发5次)
-
监控操作
# 移除ANR的监控 d.watcher.remove("ANR") # 移除所有的监控 d.watcher.remove() # 开始后台监控 d.watcher.start() d.watcher.start(2.0) # 默认监控间隔2.0s # 强制运行所有监控 d.watcher.run() # 停止监控 d.watcher.stop() # 停止并移除所有的监控,常用于初始化 d.watcher.reset()
12、XPath选择器
https://github.com/openatx/uiautomator2/blob/master/XPATH.md
注意事项: 有些属性的名字有修改需要注意
description -> content-desc
resourceId -> resource-id
-
常见用法
d.xpath("//android.widget.TextView").wait(10.0) d.xpath("//*[@content-desc='分享']").click() if d.xpath("//android.widget.TextView[contains(@text, 'Se')]").exists: print("exists") for elem in d.xpath("//android.widget.TextView").all(): print("Text:", elem.text)
-
多个条件点位(and)
d.xpath('//android.widget.Button').xpath('//*[@text="私人FM"]')
-
定位到父元素
d.xpath('@personal-fm') # 等价于 d.xpath('//*[@resource-id="personal-fm"]') d.xpath('//*[@text="私人FM"]').parent() # 定位到父元素 d.xpath('//*[@text="私人FM"]').parent("@android:list") # 定位到符合条件的父元素
-
后代元素
d.xpath('@android:id/list').child('/android.widget.TextView').click() # 等价于下面这个 d.xpath('//*[@resource-id="android:id/list"]/android.widget.TextView').click()