首页 > Python > python UIAutomator2使用超详细教程

python UIAutomator2使用超详细教程

Python 2023-01-30

一、环境要求

python 3.6+
android 4.4+

二、介绍

uiautomator2 是一个可以使用python对android设备进行ui自动化的库。其底层基于google uiautomator,google提供的uiautomator库可以获取屏幕上任意一个app的任意一个控件属性,并对其进行任意操作。

三、库地址

github地址:
https://github.com/openatx/uiautomator2

https://github.com/openatx/uiautomator2/blob/master/readme.md

四、安装

1、安装uiautomator2

1 pip install --pre uiautomator2
2 pip install pillow (如果需要截图,可安装这个库)

2、设备安装atx-agent

首先设备连接到pc,并能够adb devices发现该设备。
执行下面的命令会自动安装本库所需要的设备端程序:uiautomator-server,atx-agent,openstf / minicap,openstf / minitouch

1 # init就是所有usb连接电脑的手机上都安装uiautomator2
2 python -m uiautomator2 init
3  
4 # 指定手机安装uiautomator2, 用 --mirror
5 python -m uiautomator2 init --mirror --serial $serial
6  
7 # 嫌弃慢的话,可以用国内的镜像
8 python -m uiautomator2 init --mirror

最后提示success,代表atx-agent初始化成功。

3、安装weditor
有了这个,方便我们快速的识别手机上的元素,方便写代码

1 pip install -u weditor

安装好之后,就可以在命令行运行 weditor --help 确认是否安装成功了。

windows系统可以使用命令在桌面创建一个快捷方式:

1 weditor --shortcut

在windows cmd中执行上述命令后,会在桌面上创建一个快捷方式,如下图:

启动方法:

方法1.命令行直接输入 weditor 会自动打开浏览器,输入设备的ip或者序列号,点击connect即可;
方法2.桌面上双击weditor快捷方式即可;
方法3.命令行中执行 python -m weditor

启动后如下图:

五、应用及操作

调用uiautomator2的过程

配置手机设备参数,设置具体操作的是哪一台手机
抓取手机上应用的控件,制定对应的控件来进行操作
对抓取到的控件进行操作,比如点击、填写参数等。

设备连接方法,有两种:

python-uiautomator2连接手机的方式有两种,一种是通过wifi,另外一种是通过usb。两种方法各有优缺点。
wifi最便利的地方要数可以不用连接数据线,usb则可以用在pc和手机网络不在一个网段用不了的情况。

(1)通过wifi,假设设备ip 192.168.0.107和您的pc在同一网络中

1 import uiautomator2 as u2
2 d = u2.connect('192.168.0.107')

(2)通过usb, 假设设备序列是123456789f

1 import uiautomator2 as u2
2 d = u2.connect('123456789f') # usb链接设备。或者u2.connect_usb('123456f')
3 #d = u2.connect_usb() 或者 d = u2.connect() ,当前只有一个设备时可以用这个

在没有参数的情况下调用u2.connect(), uiautomator2将从环境变量android_device_ip获取设备ip。如果这个环境变量是空的,uiautomator将返回connect_usb,您需要确保只有一个设备连接到计算机。

检查并维持设备端守护进程处于运行状态:

1 d.healthcheck()

打开调试开关:

1 d.debug = true
2 d.info

安装应用,只能从url安装:

1 d.app_install('http://some-domain.com/some.apk') #引号内为下载apk地址

启动应用:

1 d.app_start('com.eg.android.alipaygphone') #引号内为包名称,这里为支付宝

停止应用:

1 #相当于'am force-stop'强制停止应用
2 d.app_stop('com.eg.android.alipaygphone')
3  
4 #相当于'pm clear' 清空app数据
5 d.app_clear('com.eg.android.alipaygphone')

停止所有正在运行的应用程序:

1 # 停止所有
2 d.app_stop_all()
3  
4 # 停止所有应用程序,除了com.examples.demo
5 d.app_stop_all(excludes=['com.examples.demo'])

跳过弹窗,禁止弹窗:

1 d.disable_popups() # 自动跳过弹出窗口
2 d.disable_popups(false) # 禁用自动跳过弹出窗

获取设备信息:

01 # 获取基本信息
02 d.info
03  
04 # 获取窗口大小
05 print(d.window_size())
06 # 设备垂直输出示例: (1080, 1920)
07 # 设备水平输出示例: (1920, 1080)
08  
09 # 获取当前应用程序信息。对于某些android设备,输出可以为空
10 print(d.current_app())
11  
12 #获取设备序列号
13 print(d.serial)
14  
15 #获取wifi ip
16 print(d.wlan_ip)
17  
18 #获取详细的设备信息
19 print(d.device_info)

获取应用信息:

01 d.app_info("com.eg.android.alipaygphone")
02 # 会输出
03 '''
04 {
05  "packagename": "com.eg.android.alipaygphone",
06  "mainactivity": "com.eg.android.alipaygphone.alipaylogin",
07  "label": "支付寶",
08  "versionname": "10.2.13.9020",
09  "versioncode": 360,
10  "size": 108306104
11 }
12 '''
13 # 保存应用程序图标
14 img = d.app_icon("com.eg.android.alipaygphone")
15 img.save("icon.png")

推拉文件:
(1)将文件推送到设备

1 # push文件夹
2 d.push("foo.txt", "/sdcard/")
3 # push和重命名
4 d.push("foo.txt", "/sdcard/bar.txt")
5 # push fileobj
6 with open("foo.txt", 'rb') as f:
7  d.push(f, "/sdcard/")
8 # 推动和更改文件访问模式
9 d.push("foo.sh", "/data/local/tmp/", mode=0o755)

(2)从设备中拉出一个文件

1 d.pull("/sdcard/tmp.txt", "tmp.txt")
2  
3 # 如果在设备上找不到文件,filenotfounderror将引发
4 d.pull("/sdcard/some-file-not-exists.txt", "tmp.txt")

关键事件:
(1)打开/关闭屏幕

1 d.screen_on()#打开屏幕
2 d.screen_off() #关闭屏幕

(2)获取当前屏幕状态

1 d.info.get('screenon') # 需要 android> = 4.4

(3)硬键盘和软键盘操作

01 d.press("home") # 点击home键
02 d.press("back") # 点击back键
03 d.press("left") # 点击左键
04 d.press("right") # 点击右键
05 d.press("up") # 点击上键
06 d.press("down") # 点击下键
07 d.press("center") # 点击选中
08 d.press("menu") # 点击menu按键
09 d.press("search") # 点击搜索按键
10 d.press("enter") # 点击enter键
11 d.press("delete") # 点击删除按键
12 d.press("recent") # 点击近期活动按键
13 d.press("volume_up") # 音量+
14 d.press("volume_down") # 音量-
15 d.press("volume_mute") # 静音
16 d.press("camera") # 相机
17 d.press("power") #电源键

(4)解锁屏幕

1 d.unlock()
2 # 相当于
3 # 1. 发射活动:com.github.uiautomator.action_identify
4 # 2. 按home键

手势与设备的交互:

01 # 单击屏幕
02 d.click(x,y) # x,y为点击坐标
03  
04 # 双击屏幕
05 d.double_click(x,y)
06 d.double_click(x,y,0.1) # 默认两个单击之间间隔时间为0.1秒
07  
08 # 长按
09 d.long_click(x,y)
10 d.long_click(x,y,0.5) # 长按0.5秒(默认)
11  
12 # 滑动
13 d.swipe(sx, sy, ex, ey)
14 d.swipe(sx, sy, ex, ey, 0.5) #滑动0.5s(default)
15  
16 #拖动
17 d.drag(sx, sy, ex, ey)
18 d.drag(sx, sy, ex, ey, 0.5)#拖动0.5s(default)
19 # 滑动点 多用于九宫格解锁,提前获取到每个点的相对坐标(这里支持百分比)
20  
21 # 从点(x0, y0)滑到点(x1, y1)再滑到点(x2, y2)
22 # 两点之间的滑动速度是0.2秒
23 d.swipe((x0, y0), (x1, y1), (x2, y2), 0.2)
24 # 注意:单击,滑动,拖动操作支持百分比位置值。例:
25 d.long_click(0.5, 0.5) 表示长按屏幕中心

xpath:

01 # 检索方向
02 d.orientation
03 # 检索方向。输出可以是 "natural" or "left" or "right" or "upsidedown"
04  
05 # 设置方向
06 d.set_orientation("l") # or "left"
07 d.set_orientation("r") # or "right"
08 d.set_orientation("n") # or "natural"
09  
10 #冻结/ 开启旋转
11 d.freeze_rotation() # 冻结旋转
12 d.freeze_rotation(false) # 开启旋转
13  
14 ########## 截图 ############
15 # 截图并保存到电脑上的一个文件中,需要android>=4.2。
16 d.screenshot("home.jpg")
17  
18 # 得到pil.image格式的图像. 但你必须先安装pillow
19 image = d.screenshot() # default format="pillow"
20 image.save("home.jpg") # 或'home.png',目前只支持png 和 jpg格式的图像
21  
22 # 得到opencv的格式图像。当然,你需要numpy和cv2安装第一个
23 import cv2
24 image = d.screenshot(format='opencv')
25 cv2.imwrite('home.jpg', image)
26  
27 # 获取原始jpeg数据
28 imagebin = d.screenshot(format='raw')
29 open("some.jpg", "wb").write(imagebin)
30  
31 #############################
32  
33 # 转储ui层次结构
34 # get the ui hierarchy dump content (unicoded).(获取ui层次结构转储内容)
35 d.dump_hierarchy()
36  
37  
38 # 打开通知或快速设置
39 d.open_notification() #下拉打开通知栏
40 d.open_quick_settings() #下拉打开快速设置栏
41  
42 # 检查特定的ui对象是否存在
43 d(text="settings").exists # 返回布尔值,如果存在则为true,否则为false
44 d.exists(text="settings") # 另一种写法
45 # 高级用法
46 d(text="settings").exists(timeout=3) # 等待'settings'在3秒钟出现
47  
48 # 获取特定ui对象的信息
49 d(text="settings").info
50  
51 # 获取/设置/清除可编辑字段的文本(例如edittext小部件)
52 d(text="settings").get_text() #得到文本小部件
53 d(text="settings").set_text("my text...") #设置文本
54 d(text="settings").clear_text() #清除文本
55  
56 # 获取widget中心点
57 d(text="settings").center()
58 #d(text="settings").center(offset=(0, 0)) # 基准位置左前

ui对象有五种定位方式:

01 # text、resourceid、description、classname、xpath、坐标
02  
03 # 执行单击ui对象
04 #text定位单击
05 d(text="settings").click()
06 d(text="settings", classname="android.widget.textview").click()
07  
08 #resourceid定位单击
09 d(resourceid="com.ruguoapp.jike:id/tv_title", classname="android.widget.textview").click()
10  
11 #description定位单击
12 d(description="设置").click()
13 d(description="设置", classname="android.widget.textview").click()
14  
15 #classname定位单击
16 d(classname="android.widget.textview").click()
17  
18 #xpath定位单击
19 d.xpath("//android.widget.framelayout[@index='0']/android.widget.linearlayout[@index='0']").click()
20  
21 #坐标单击
22 d.click(182, 1264)
23  
24 # 等待元素出现(最多10秒),出现后单击
25 d(text="settings").click(timeout=10)
26 # 在10秒时点击,默认的超时0
27 d(text='skip').click_exists(timeout=10.0)
28 # 单击直到元素消失,返回布尔
29 d(text="skip").click_gone(maxretry=10, interval=1.0) # maxretry默认值10,interval默认值1.0
30 # 点击基准位置偏移
31 d(text="settings").click(offset=(0.5, 0.5)) # 点击中心位置,同d(text="settings").click()
32 d(text="settings").click(offset=(0, 0)) # 点击左前位置
33 d(text="settings").click(offset=(1, 1)) # 点击右下
34  
35 # 执行双击ui对象
36 d(text="设置").double_click() # 双击特定ui对象的中心
37 d.double_click(x, y, 0.1) # 两次单击之间的默认持续时间为0.1秒
38  
39 #执行长按ui对象
40 # 长按特定ui对象的中心
41 d(text="settings").long_click()
42 d.long_click(x, y, 0.5) # 长按坐标位置0.5s默认
43  
44 # 将ui对象拖向另一个点或另一个ui对象
45 # android<4.3不能使用drag.
46 # 在0.5秒内将ui对象拖到屏幕点(x, y)
47 d(text="settings").drag_to(x, y, duration=0.5)
48  
49 # 将ui对象拖到另一个ui对象的中心位置,时间为0.25秒
50 d(text="settings").drag_to(text="clock", duration=0.25)

常见用法:

01 # 等待10s
02 d.xpath("//android.widget.textview").wait(10.0)
03  
04 # 找到并单击
05 d.xpath("//*[@content-desc='分享']").click()
06  
07 # 检查是否存在
08 if d.xpath("//android.widget.textview[contains(@text, 'se')]").exists:
09  print("exists")
10  
11 # 获取所有文本视图文本、属性和中心点
12 for elem in d.xpath("//android.widget.textview").all():
13  print("text:", elem.text)
14  
15 #获取视图文本
16 for elem in d.xpath("//android.widget.textview").all():
17  print("attrib:", elem.attrib)
18  
19 #获取属性和中心点
20 #返回: (100, 200)
21 for elem in d.xpath("//android.widget.textview").all():
22  print("position:", elem.center())
23  
24 # xpath常见用法:
25 # 所有元素
26 //*
27  
28 # resource-id包含login字符
29 //*[contains(@resource-id, 'login')]
30  
31 # 按钮包含账号或帐号
32 //android.widget.button[contains(@text, '账号') or contains(@text, '帐号')]
33  
34 # 所有imageview中的第二个
35 (//android.widget.imageview)[2]
36  
37 # 所有imageview中的最后一个
38 (//android.widget.imageview)[last()]
39  
40 # classname包含imageview
41 //*[contains(name(), "imageview")]