移动端自动化之uiautomator2
github: https://github.com/openatx/uiautomator2
[安装]
pip3 install -U uiautomator2
# 安装UI Inspector --> 便于查找元素(
浏览器打开 https://uiauto.dev 查看当前设备的界面结构
)
pip install uiautodev
# 启动服务
uiauto.dev
[使用]
import uiautomator2 as u2 d = u2.connect() # connect to device print(d.info)
# 使用设备序列号连接(使用adb devices查看)
d = u2.connect('123456f') # alias for u2.connect_usb('123456f')
# 可以指定环境变量
# export ANDROID_SERIAL=123456f
# 使用WiFi的方式连接(adb使用wifi连接设备:https://www.cnblogs.com/lihongtaoya/p/17553171.html)
d = u2.connect("ip:proxy") # wifi连接设备
元素定位页面:
常用方法:
常用定位方式: ResourceId定位: d(resourceId="com.meizu.mzbbs:id/tp").click() Text定位:(很有用) d(text="精选").click() Description定位: d(description="..").click() ClassName定位: d(className="android.widget.TextView").click()
支持组合定位: 同时指定className和textd(className
=
"android.widget.TextView"
, text
=
u
"好友动态"
)
使用xpath定位:d.xpath('
//*[@resource-id="com.tencent.mobileqq:id/ivTitleBtnRightImage"]'
)
使用相邻节点定位:d(text
=
"小窝"
).sibling(resourceId
=
"com.tencent.mobileqq:id/yx"
).click()
1.点击
# click点击 d(description="点按两次并按住可长按进入多选模式").click() # 也可更加某点就行点击d.click(0.1,0.1) # 单击直到元素消失,点击间隔1s,maxretry超时时长 d(description="点按两次并按住可长按进入多选模式").click_gone(maxretry=5, interval=1)
2.长按
# 长按long_click d(description="点按两次并按住可长按进入多选模式").long_click()
3.文本
# 文本 d.send_keys("1234") # 光标停留在输入框后直接sendkeys,自动切换fastinputime输入法 d.clear_text() # 光标停留在输入框清空内容
4.拖拽
1)元素到元素拖拽
# 元素到元素拖拽drag_to d(text="SecoClient").drag_to(text="哔哩哔哩", duration=0.25) # 将元素SecoClient拖到”哔哩哔哩“的位置,时间0.25s
2)元素到坐标拖拽
# 元素到坐标的拖拽 drag_to d(text="SecoClient").drag_to(0.603, 0.587, duration=0.25)
3)坐标到坐标拖拽
# 两个坐标之间拖拽drag d.drag(x1,y1,x2,y2)
5.滑动
1)元素滚动
# 元素滑动"left", "right", "up", "down" 左右上下,一个步长5ms,20个step是100ms d(text="SecoClient").swipe("up", steps=20) # 将元素向上拖拽,时长100ms
2)屏幕滚动
# 屏幕滑动 x, y = d.window_size() # 获取屏幕分辨率 x1 = x * 0.1 y1 = y * 0.3 y2 = y * 0.6 d.swipe(x1, y1, x1, y2) # 手势向下滑,从竖屏30%的地方滑到60%的位置 d.swipe(x*0.9, y*0.1, x*0.1, y*0.1) # 向右滑,从横屏90%的地方滑到10%的位置
也可直接操作滑动
# 直接滑动 "left", "right", "up", "down" 左右上下 d.swipe_ext("left")
3)界面滚动
滚动类型:horiz 为水平 vert 为垂直
滚动方向:forward 向前 , backward 向后 , toBeginning 滚动至开始 , toEnd 滚动至最后 ,to 滚动直接某个元素出现
# 界面滚动(界面是否可以滚动) 不太好用 d(scrollable=True).scroll.vert.toBeginning() # 垂直滚动到页面顶部(不填vert,默认就是垂直) d(scrollable=True).scroll.vert.toEnd() # 垂直滚动到页面底部 d(scrollable=True).scroll.horiz.toEnd() # 水平滚动置末尾,即最右侧 d(scrollable=True).scroll.horiz.toBeginning() # 水平滚动置开头,即最左侧 d(scrollable=True).scroll.horiz.forward() # 水平向前滚动一下 d(scrollable=True).scroll.horiz.backward() # 水平向后滚动一下 d(scrollable=True).scroll.vert.forward() # 垂直向下滚动一下 d(scrollable=True).scroll.vert.backward() # 垂直向上滚动一下
滚动置某一个元素停下来
# 滚动置某个元素停下 d(scrollable=True).scroll.vert.backward.to(resourceId="id/title", text="《系列》电影") # 水平向上滚动到指定元素停下,向上找不到元素会往下滚动 d(scrollable=True).scroll.vert.toBeginning.to(text="SDK") # 垂直向上到指定元素停下,向上到顶部找不到元素会往下滚动
4)连续滚动
d.touch.down(x,y) 按住某个点
d.touch.sleep(5) 停留5s
d.touch.move(x,y) 移动到某点
d.touch.up(x,y) 在某点松开
# 连续滑动 touch(手机图案解锁) d.touch.down(0.841, 0.477).sleep(3).up(0.841, 0.477) # 在0.841, 0.477点击3s后松开,实现长按 # 从0.841, 0.477移动到0.827, 0.234后在0.186, 0.268松开,开始点击的时候长按0.2s,因为touch执行的特别快,按住图标后手机程序还没反应过来就结束了,导致滑动没有任何效果 d.touch.down(0.841, 0.477).sleep(0.2).move(0.827, 0.234).move(0.186, 0.268).up(0.186, 0.268)
6.放大缩小
# 放大缩小 d(resourceId="com.vivo.gallery:id/gallery_root_bottom").pinch_in() # 缩小 d(resourceId="com.vivo.gallery:id/gallery_root_bottom").pinch_out() # 放大 # 指定放大缩小范围(单指1初位置)(单指2初位置)(滑动后单指1的位置)(滑动后单指2的位置) d(resourceId="com.vivo.gallery:id/gallery_root_bottom").gesture((0.51, 0.327),(0.51,0.484),(0.51,0.147),(0.51,0.772))
7.等待元素出现/消失
# 等待元素出现或消失 bol = d(text="哈哈").wait(timeout=3.0) # 等待元素出现,时长3s,3s内出现返回true,未出现返回false bol=d(text='哈哈').wait_gone(timeout=3) # 等待元素消失,时长3s,3s内消失true,未消失返回false
8.按键
# 按键 d.press("enter") # 目前仅支持 home, back, left, right, up, down, center, menu, search, enter,delete(or del), recent(recent apps), volume_up, volume_down,volume_mute, camera, power # 或 d.keyevent("enter")
9.输入法切换
# 输入法切换 d.set_fastinput_ime(True) # 设置默认输入法与fastinputime输入法转变(True为fastinputime,false默认输入法) print(d.current_ime()) # 查看当前输入法
10.模拟fastinputime输入法键盘操作
# 模拟fastinputime输入法键盘操作 d.send_action(5) # 下一步 # 或 d.send_action("next") # 目前仅支持如下几个 """ "go": 2, "search": 3, "send": 4, "next": 5, "done": 6, "previous": 7 """
11.截图
# 截图 d.screenshot("test.png") # 当前项目目录下
12.录制
1)安装依赖:pip install -U "uiautomator2[image]"
2)方法
d.screenrecord('test.mp4') # 开始 time.sleep(2) d.screenrecord.stop() # 结束
13.应用管理操作
1)获取当前页面信息
print(d.app_current()) # 获取当前页面信息:package,activity,pid
2)安装app
d.app_install("url") # 安装app
3)启动app
d.app_start("package_name")
4)获取app信息
print(d.app_info("package_name")) # 获取app信息
5)退出应用
退到后台
d.app_stop("package_name") # 返回主界面
清除缓存(杀进程)
d.app_clear("package_name") # 杀进程清除缓存
6)获取设备ip
print(d.wlan_ip) # 手机ip
7)获取设备信息(cpu,电池等)
print(d.device_info) # 获取设备信息(型号,cpu,电池等信息)
8)卸载app
d.app_uninstall('tv.danmaku.bili') # 卸载
9)等待应用启动
""" 等待应用变为当前应用,返回pid,超时未启动成功则返回0 front为true表示等待app成为当前app, 默认为false,表示只要后台有这个应用的进程就会返回PID """ a=d.app_wait("com.tencent.wework",6,front=True) # 返回pid print(a)
13.全局设置
1)查看默认配置
print(d.settings) """ { 'fallback_to_blank_screenshot': False, 'operation_delay': (0, 5), 点击元素后延迟0-5秒 'operation_delay_methods': ['click', 'swipe'], 点击元素延迟时间生效的方法(可以增加press,send_keys等 ) 'wait_timeout': 20.0, 查找元素默认等待时长 'xpath_debug': False xpath日志 } """
2)修改默认配置
d.settings["wait_timeout"]=10 # 修改设置,按照字典来修改即可
全局等待时长还可通过implicitly_wait来设置
d.implicitly_wait(10)
14.息/亮屏
d.screen_off() # 息屏(锁屏) d.sleep(5) d.screen_on() # 亮屏
15.通知栏操作
d.open_notification() # 打开通知栏 d.open_quick_settings() # 打开通知栏设置页
16.停止ATX服务
d.service("uiautomator").stop() # 停止atx服务
17.读取devices信息
print(d.info)
示例:
1.小红书搜索
import json import random import time import uiautomator2 as u2 serial_number = '712KPMZ11437' # 也可以通过环境的方式 export ANDROID_SERIAL=123456f d = u2.connect(serial_number) print(d.info) time.sleep(2) package_name = 'com.tencent.mm' # package_name = 'com.xingin.xhs' app_info = d.app_info(package_name) # 查看应用信息, 是否已经安装 print('应用信息:',json.dumps(app_info, ensure_ascii=False)) # {"versionName": "8.46.0", "versionCode": 8460909} print('设备信息:', d.device_info) # {'serial': '712KPMZ11437', 'sdk': 30, 'brand': 'google', 'model': 'Pixel 2 XL', 'arch': 'arm64-v8a', 'version': 11} print('窗口尺寸:', d.window_size()) # (1440, 2880) print('当前APP:', d.app_current()) # {'package': 'com.tencent.mm', 'activity': '.ui.LauncherUI', 'pid': 27494} print('设备序列号:', d.serial) # 712KPMZ11437 print('获取WLAN的IP:', d.wlan_ip) # 192.168.1.11 d.app_start(package_name) # 打开应用程序 time.sleep(random.uniform(3, 10)) # 返回一个指定范围内的浮点数(包含) def xhs(): print('点击搜索...') d(resourceId="com.xingin.xhs:id/i8p").click() time.sleep(random.uniform(1, 5)) print('输入内容...') # 输入内容 d(resourceId="com.xingin.xhs:id/frt").clear_text() uid = "chenger261" d(resourceId="com.xingin.xhs:id/frt").send_keys(uid) time.sleep(random.uniform(1, 5)) d.press("enter") print('进行搜索') for _ in range(0, 3): # 滑动操作 d.swipe_ext('up', scale=0.8) time.sleep(random.uniform(1, 3)) # 关闭应用 d.app_stop(package_name) # 只关闭指定应用
2.微信指定链接点击
import json import random import time import uiautomator2 as u2 serial_number = '712KPMZ11437' # 也可以通过环境的方式 export ANDROID_SERIAL=123456f d = u2.connect(serial_number) print(d.info) time.sleep(2) package_name = 'com.tencent.mm' d.app_start(package_name) time.sleep(random.uniform(3, 10)) # 返回一个指定范围内的浮点数(包含) def wechat(): # 找到指定对话框 print('点击进入文件传输助手...') # 方式1 # d(text="文件传输助手").click(timeout=3) # 方式2 d(className="android.widget.LinearLayout").child(text='文件传输助手').click(timeout=3) print('已经进入文件传输助手!!!') time.sleep(3) # 点击指定链接 print('点击指定链接地址') d(text="https://www.cnblogs.com/xingxia").click(timeout=3) time.sleep(5) # 返回 d.press('back') d.press('back')
更多参考: