UiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务。功能很强,可以对第三方App进行测试,获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作,但有两个缺点:1. 测试脚本只能使用Java语言 2. 测试脚本要打包成jar或者apk包上传到设备上才能运行。

我们希望测试逻辑能够用Python编写,能够在电脑上运行的时候就控制手机。这里要非常感谢 Xiaocong He (@xiaocong),他将这个想法实现了出来(见xiaocong/uiautomator),原理是在手机上运行了一个http rpc服务,将uiautomator中的功能开放出来,然后再将这些http接口封装成Python库。 因为xiaocong/uiautomator这个库,已经很久不见更新。所以我们直接fork了一个版本,为了方便做区分我们就在后面加了个2 openatx/uiautomator2

除了对原有的库的bug进行了修复,还增加了很多新的Feature。主要有以下部分:

设备和开发机可以脱离数据线,通过WiFi互联(基于atx-agent)
集成了openstf/minicap达到实时屏幕投频,以及实时截图
集成了openstf/minitouch达到精确实时控制设备
修复了xiaocong/uiautomator经常性退出的问题
代码进行了重构和精简,方便维护
实现了一个设备管理平台(也支持iOS) atxserver2
这里要先说明下,因为经常有很多人问 openatx/uiautomator2 并不支持iOS测试,需要iOS自动化测试,可以转到这个库 openatx/facebook-wda。

PS: 这个库 https://github.com/NeteaseGame/ATX 目前已经不维护了,请尽快更换。

Requirements
Android版本 4.4+
Python 3.6+
如果仍在用python2, 需要使用命令pip install -U "uiautomator2<=1.0.0"安装

QUICK START
先准备一台(不要两台)开启了开发者选项的安卓手机,连接上电脑,确保执行adb devices可以看到连接上的设备。

运行pip3 install -U uiautomator2安装uiautomator2
运行python3 -m uiautomator2 init安装包含httprpc服务的apk到手机+atx-agent, minicap, minitouch
一般情况下都会成功,不过也可能会有意外。可以加QQ群反馈问题,群里有很多大佬可以帮你解决问题。

命令行运行python打开python交互窗口。然后将下面的命令输入到窗口中。

import uiautomator2 as u2

d = u2.connect() # connect to device
print(d.info)
这时看到类似下面的输出,就可以正式开始用我们这个库了。因为这个库功能太多,后面还有很多的内容,需要慢慢去看 …

{‘currentPackageName’: ‘net.oneplus.launcher’, ‘displayHeight’: 1920, ‘displayRotation’: 0, ‘displaySizeDpX’: 411, ‘displaySizeDpY’: 731, ‘displayWidth’: 1080, ‘productName’: ‘OnePlus5’, ’
screenOn’: True, ‘sdkInt’: 27, ‘naturalOrientation’: True}
相关项目
设备管理平台,设备多了就会用到 atxserver2
专门与adb进行交互的库 adbutils
https://github.com/openatx/atx-agent
weditor[https://github.com/openatx/weditor] 类似于uiautomatorviewer,专门为本项目开发的辅助编辑器
Installation

Connect to a device

Command line

Global settings

Debug HTTP requests
Implicit wait
App management

Install an app
Launch an app
Stop an app
Stop all running apps
Push and pull files
Auto click permission dialogs
UI automation

Shell commands
Session
Retrieve the device info
Key Events
Gesture interaction with the device
Screen-related
Selector
Watcher
Global settings
Input method
Toast
XPath
常见问题

停止UiAutomator守护服务,释放AccessibilityService
502错误
Connection Error, 深度睡眠, 点击偏差 等
实验性功能

远程投屏
htmlreport
诊断uiautomator2方法
Plugin
Hooks
失败时弹出提示框
项目历史

Contributors

LICENSE

Installation
Install uiautomator2

Since uiautomator2 is still under development, you have to add --pre to install the development version

pip install --upgrade --pre uiautomator2

Or you can install directly from github source

git clone https://github.com/openatx/uiautomator2
pip install -e uiautomator2
Optionally, pillow is needed to process screenshot data.

pip install pillow
Install daemons to a device 电脑连接上一个手机或多个手机, 确保adb已经添加到环境变量中,执行下面的命令会自动安装本库所需要的设备端程序:uiautomator-server 、atx-agent、openstf/minicap、openstf/minitouch

init 所有的已经连接到电脑的设备

python -m uiautomator2 init
有时候init也会出错,请参考手动Init指南

安装提示success即可

Install weditor (UI Inspector)

因为uiautomator是独占资源,所以当atx运行的时候uiautomatorviewer是不能用的,为了减少atx频繁的启停,我们开发了基于浏览器技术的weditor UI查看器。https://github.com/openatx/weditor

安装方法(备注: 目前最新的稳定版为 0.1.0)

pip install -U weditor
Windows系统可以使用命令在桌面创建一个快捷方式 python -m weditor --shortcut

命令行启动 python -m weditor 会自动打开浏览器,输入设备的ip或者序列号,点击Connect即可。

具体参考文章:浅谈自动化测试工具python-uiautomator2

【可选】AppetizerIO 所见即所得脚本编辑器

AppetizerIO 提供了对uiautomator2的深度集成,可以图形化管理ATX设备,还有所见即所得脚本编辑器

到网站下载直接打开,首次使用需要注册账号
设备管理 界面里可以检查设备是否正常init,起停atx-agent,抓取atx-agent.log文件
APP测试->脚本助手调出脚本助手,实时界面同步,点击界面直接插入各种代码,同时支持uiautomator和Appium
视频教程 请戳这里 其他文档在此
Connect to a device
There are two ways to connect to the device.

Through WiFi
Suppose device IP is 10.0.0.1 and your PC is in the same network.

import uiautomator2 as u2

d = u2.connect(‘10.0.0.1’) # alias for u2.connect_wifi(‘10.0.0.1’)
print(d.info)
Through USB
Suppose the device serial is 123456f (seen from adb devices)

import uiautomator2 as u2

d = u2.connect(‘123456f’) # alias for u2.connect_usb(‘123456f’)
print(d.info)
Through ADB WiFi
import uiautomator2 as u2

d = u2.connect_adb_wifi(“10.0.0.1:5555”)

Equals to

+ Shell: adb connect 10.0.0.1:5555

+ Python: u2.connect_usb(“10.0.0.1:5555”)

Calling u2.connect() with no argument, uiautomator2 will obtain device IP from the environment variable ANDROID_DEVICE_IP. If this environment variable is empty, uiautomator will fall back to connect_usb and you need to make sure that there is only one device connected to the computer.

Command line
其中的$device_ip代表设备的ip地址

如需指定设备需要传入–serial 如 python3 -m uiautomator2 --serial bff1234 , SubCommand为子命令(init,或者screenshot等)

1.0.3 Added: python3 -m uiautomator2可以简写为uiautomator2

init: 为设备安装所需要的程序

uiautomator2 init

If you need specify device to init, pass --serial

python3 -m uiautomator2 init --serial your-device-serial
screenshot: 截图

$ python -m uiautomator2 screenshot screenshot.jpg
uninstall: 卸载

python -m uiautomator2 uninstall # 卸载一个包
python -m uiautomator2 uninstall # 卸载多个包
python -m uiautomator2 uninstall --all # 全部卸载
install: 安装apk,apk通过URL给出 (暂时不能用)

clear-cache: 清空缓存 (废弃中,目前已经不需要改接口)

app-stop-all: 停止所有应用 (暂不能用)

healthcheck: 健康检查 (咱不能用)

API Documents
Global settings
This part contains some global settings

Debug HTTP requests
Trace HTTP requests and response to find out how it works.

d.debug = True
d.info
12:32:47.182 $ curl -X POST -d ‘{“jsonrpc”: “2.0”, “id”: “b80d3a488580be1f3e9cb3e926175310”, “method”: “deviceInfo”, “params”: {}}’ ‘http://127.0.0.1:54179/jsonrpc/0’
12:32:47.225 Response >>>
{“jsonrpc”:“2.0”,“id”:“b80d3a488580be1f3e9cb3e926175310”,“result”:{“currentPackageName”:“com.android.mms”,“displayHeight”:1920,“displayRotation”:0,“displaySizeDpX”:360,“displaySizeDpY”:640,“displayWidth”:1080,“productName”
:“odin”,“screenOn”:true,“sdkInt”:25,“naturalOrientation”:true}}
<<< END
Implicit wait
Set default element wait time, unit seconds

d.implicitly_wait(10.0)
d(text=“Settings”).click() # if Settings button not show in 10s, UiObjectNotFoundError will raised

print(“wait timeout”, d.implicitly_wait()) # get default implicit wait
This function will have influence on click, long_click, drag_to, get_text, set_text, clear_text, etc.

App management
This part showcases how to perform app management

Install an app
We only support installing an APK from a URL

d.app_install(‘http://some-domain.com/some.apk’)
Launch an app
d.app_start(“com.example.hello_world”) # start with package name
Stop an app

equivalent to am force-stop, thus you could lose data

d.app_stop(“com.example.hello_world”)

equivalent to pm clear

d.app_clear(‘com.example.hello_world’)
Stop all running apps

stop all

d.app_stop_all()

stop all app except for com.examples.demo

d.app_stop_all(excludes=[‘com.examples.demo’])
Get app info
d.app_info(“com.examples.demo”)

expect output

#{

“mainActivity”: “com.github.uiautomator.MainActivity”,

“label”: “ATX”,

“versionName”: “1.1.7”,

“versionCode”: 1001007,

“size”:1760809

#}

save app icon

img = d.app_icon(“com.examples.demo”)
img.save(“icon.png”)
Push and pull files
push a file to the device

push to a folder

d.push(“foo.txt”, “/sdcard/”)

push and rename

d.push(“foo.txt”, “/sdcard/bar.txt”)

push fileobj

with open(“foo.txt”, ‘rb’) as f:
d.push(f, “/sdcard/”)

push and change file access mode

d.push(“foo.sh”, “/data/local/tmp/”, mode=0o755)
pull a file from the device

d.pull("/sdcard/tmp.txt", “tmp.txt”)

FileNotFoundError will raise if the file is not found on the device

d.pull("/sdcard/some-file-not-exists.txt", “tmp.txt”)
检查并维持设备端守护进程处于运行状态
d.healthcheck()
Auto click permission dialogs
注意注意 disable_popups函数,检测发现很不稳定,暂时不要使用,等候通知。

Import in version 0.1.1

d.disable_popups() # automatic skip popups
d.disable_popups(False) # disable automatic skip popups
popup

If this method is not working on your device, You can make a pull request or create an issue to enhance this function. I’ll show you how to do it.

Open uiautomatorviewer.bat
Get popup hierarchy
hierarchy

Now you know the button text and current package name. Make a pull request by update function disable_popups or create an issue if you are not familar with git and python.

Basic API Usages
This part showcases how to perform common device operations:

Shell commands
Run a short-lived shell command with a timeout protection. (Default timeout 60s)

Note: timeout support require atx-agent >=0.3.3

adb_shell function is deprecated. Use shell instead.

Simple usage

output, exit_code = d.shell(“pwd”, timeout=60) # timeout 60s (Default)

output: “/\n”, exit_code: 0

Similar to command: adb shell pwd

Since shell function return type is namedtuple("ShellResponse", ("output", "exit_code"))

so we can do some tricks

output = d.shell(“pwd”).output
exit_code = d.shell(“pwd”).exit_code
The first argument can be list. for example

output, exit_code = d.shell([“ls”, “-l”])

output: “/…”, exit_code: 0

This returns a string for stdout merged with stderr. If the command is a blocking command, shell will also block until the command is completed or the timeout kicks in. No partial output will be received during the execution of the command. This API is not suitable for long-running commands. The shell command given runs in a similar environment of adb shell, which has a Linux permission level of adb or shell (higher than an app permission).

Run a long-running shell command

add stream=True will return requests.models.Response object. More info see requests stream

r = d.shell(“logcat”, stream=True)

r: requests.models.Response

deadline = time.time() + 10 # run maxium 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() # this method must be called
Command will be terminated when r.close() called.

Session
Session represent an app lifecycle. Can be used to start app, detect app crash.

Launch and close app

sess = d.session(“com.netease.cloudmusic”) # start 网易云音乐
sess.close() # 停止网易云音乐
Use python with to launch and close app

with d.session(“com.netease.cloudmusic”) as sess:
sess(text=“Play”).click()
Attach to the running app

sess = d.session(“com.netease.cloudmusic”, attach=True)
Detect app crash

When app is still running

sess(text=“Music”).click() # operation goes normal

If app crash or quit

sess(text=“Music”).click() # raise SessionBrokenError

other function calls under session will raise SessionBrokenError too

check if session is ok.

Warning: function name may change in the future

sess.running() # True or False
Retrieve the device info
Get basic information

d.info
Below is a possible output:

{
u’displayRotation’: 0,
u’displaySizeDpY’: 640,
u’displaySizeDpX’: 360,
u’currentPackageName’: u’com.android.launcher’,
u’productName’: u’takju’,
u’displayWidth’: 720,
u’sdkInt’: 18,
u’displayHeight’: 1184,
u’naturalOrientation’: True
}
Get window size

print(d.window_size())

device upright output example: (1080, 1920)

device horizontal output example: (1920, 1080)

Get current app info. For some android devices, the output could be empty (see Output example 3)

print(d.current_app())

Output example 1: {‘activity’: ‘.Client’, ‘package’: ‘com.netease.example’, ‘pid’: 23710}

Output example 2: {‘activity’: ‘.Client’, ‘package’: ‘com.netease.example’}

Output example 3: {‘activity’: None, ‘package’: None}

Wait activity

d.wait_activity(".ApiDemos", timeout=10) # default timeout 10.0 seconds

Output: true of false

Get device serial number

print(d.serial)

output example: 74aAEDR428Z9

Get WLAN ip

print(d.wlan_ip)

output example: 10.0.0.1

Get detailed device info

print(d.device_info)
Below is a possible output:

{‘udid’: ‘3578298f-b4:0b:44:e6:1f:90-OD103’,
‘version’: ‘7.1.1’,
‘serial’: ‘3578298f’,
‘brand’: ‘SMARTISAN’,
‘model’: ‘OD103’,
‘hwaddr’: ‘b4:0b:44:e6:1f:90’,
‘port’: 7912,
‘sdk’: 25,
‘agentVersion’: ‘dev’,
‘display’: {‘width’: 1080, ‘height’: 1920},
‘battery’: {‘acPowered’: False,
‘usbPowered’: False,
‘wirelessPowered’: False,
‘status’: 3,
‘health’: 0,
‘present’: True,
‘level’: 99,
‘scale’: 100,
‘voltage’: 4316,
‘temperature’: 272,
‘technology’: ‘Li-ion’},
‘memory’: {‘total’: 3690280, ‘around’: ‘4 GB’},
‘cpu’: {‘cores’: 8, ‘hardware’: ‘Qualcomm Technologies, Inc MSM8953Pro’},
‘presenceChangedAt’: ‘0001-01-01T00:00:00Z’,
‘usingBeganAt’: ‘0001-01-01T00:00:00Z’}
Key Events
Turn on/off screen

d.screen_on() # turn on the screen
d.screen_off() # turn off the screen
Get current screen status

d.info.get(‘screenOn’) # require Android >= 4.4
Press hard/soft key

d.press(“home”) # press the home key, with key name
d.press(“back”) # press the back key, with key name
d.press(0x07, 0x02) # press keycode 0x07(‘0’) with META ALT(0x02)
These key names are currently supported:

home
back
left
right
up
down
center
menu
search
enter
delete ( or del)
recent (recent apps)
volume_up
volume_down
volume_mute
camera
power
You can find all key code definitions at Android KeyEvnet

Unlock screen

d.unlock()

This is equivalent to

1. launch activity: com.github.uiautomator.ACTION_IDENTIFY

2. press the “home” key

Gesture interaction with the device
Click on the screen

d.click(x, y)
Double click

d.double_click(x, y)
d.double_click(x, y, 0.1) # default duration between two click is 0.1s
Long click on the screen

d.long_click(x, y)
d.long_click(x, y, 0.5) # long click 0.5s (default)
Swipe

d.swipe(sx, sy, ex, ey)
d.swipe(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
Drag

d.drag(sx, sy, ex, ey)
d.drag(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
Swipe points

swipe from point(x0, y0) to point(x1, y1) then to point(x2, y2)

time will speed 0.2s bwtween two points

d.swipe_points([(x0, y0), (x1, y1), (x2, y2)], 0.2))
多用于九宫格解锁,提前获取到每个点的相对坐标(这里支持百分比), 更详细的使用参考这个帖子 使用u2实现九宫图案解锁

Touch and drap (Beta)

这个接口属于比较底层的原始接口,感觉并不完善,不过凑合能用。注:这个地方并不支持百分比

d.touch.down(10, 10) # 模拟按下
time.sleep(.01) # down 和 move 之间的延迟,自己控制
d.touch.move(15, 15) # 模拟移动
d.touch.up() # 模拟抬起
Note: click, swipe, drag operations support percentage position values. Example:

d.long_click(0.5, 0.5) means long click center of screen

Screen-related
Retrieve/Set device orientation

The possible orientations:

natural or n
left or l
right or r
upsidedown or u (can not be set)

retrieve orientation. the output could be “natural” or “left” or “right” or “upsidedown”

orientation = d.orientation

WARNING: not pass testing in my TT-M1

set orientation and freeze rotation.

notes: setting “upsidedown” requires Android>=4.3.

d.set_orientation(‘l’) # or “left”
d.set_orientation(“l”) # or “left”
d.set_orientation(“r”) # or “right”
d.set_orientation(“n”) # or “natural”
Freeze/Un-freeze rotation

freeze rotation

d.freeze_rotation()

un-freeze rotation

d.freeze_rotation(False)
Take screenshot

take screenshot and save to a file on the computer, require Android>=4.2.

d.screenshot(“home.jpg”)

get PIL.Image formatted images. Naturally, you need pillow installed first

image = d.screenshot() # default format=“pillow”
image.save(“home.jpg”) # or home.png. Currently, only png and jpg are supported

get opencv formatted images. Naturally, you need numpy and cv2 installed first

import cv2
image = d.screenshot(format=‘opencv’)
cv2.imwrite(‘home.jpg’, image)

get raw jpeg data

imagebin = d.screenshot(format=‘raw’)
open(“some.jpg”, “wb”).write(imagebin)
Dump UI hierarchy

get the UI hierarchy dump content (unicoded).

xml = d.dump_hierarchy()
Open notification or quick settings

d.open_notification()
d.open_quick_settings()
Selector
Selector is a handy mechanism to identify a specific UI object in the current window.

Select the object with text ‘Clock’ and its className is ‘android.widget.TextView’

d(text=‘Clock’, className=‘android.widget.TextView’)
Selector supports below parameters. Refer to UiSelector Java doc for detailed information.

text, textContains, textMatches, textStartsWith
className, classNameMatches
description, descriptionContains, descriptionMatches, descriptionStartsWith
checkable, checked, clickable, longClickable
scrollable, enabled,focusable, focused, selected
packageName, packageNameMatches
resourceId, resourceIdMatches
index, instance
Children and siblings
children

get the children or grandchildren

d(className=“android.widget.ListView”).child(text=“Bluetooth”)
siblings

get siblings

d(text=“Google”).sibling(className=“android.widget.ImageView”)
children by text or description or instance

get the child matching the condition className=“android.widget.LinearLayout”

and also its children or grandchildren with text “Bluetooth”

d(className=“android.widget.ListView”, resourceId=“android:id/list”)
.child_by_text(“Bluetooth”, className=“android.widget.LinearLayout”)

get children by allowing scroll search

d(className=“android.widget.ListView”, resourceId=“android:id/list”)
.child_by_text(
“Bluetooth”,
allow_scroll_search=True,
className=“android.widget.LinearLayout”
)
child_by_description is to find children whose grandchildren have the specified description, other parameters being similar to child_by_text.

child_by_instance is to find children with has a child UI element anywhere within its sub hierarchy that is at the instance specified. It is performed on visible views without scrolling.

See below links for detailed information:

UiScrollable, getChildByDescription, getChildByText, getChildByInstance
UiCollection, getChildByDescription, getChildByText, getChildByInstance
Above methods support chained invoking, e.g. for below hierarchy

<node index=“0” text="" resource-id=“android:id/list” class=“android.widget.ListView” …>
<node index=“0” text=“WIRELESS & NETWORKS” resource-id="" class=“android.widget.TextView” …/>
<node index=“1” text="" resource-id="" class=“android.widget.LinearLayout” …>
<node index=“1” text="" resource-id="" class=“android.widget.RelativeLayout” …>
<node index=“0” text=“Wi‑Fi” resource-id=“android:id/title” class=“android.widget.TextView” …/>

<node index=“2” text=“ON” resource-id=“com.android.settings:id/switchWidget” class=“android.widget.Switch” …/>

settings

To click the switch widget right to the TextView ‘Wi‑Fi’, we need to select the switch widgets first. However, according to the UI hierarchy, more than one switch widgets exist and have almost the same properties. Selecting by className will not work. Alternatively, the below selecting strategy would help:

d(className=“android.widget.ListView”, resourceId=“android:id/list”)
.child_by_text(“Wi‑Fi”, className=“android.widget.LinearLayout”)
.child(className=“android.widget.Switch”)
.click()
relative positioning

Also we can use the relative positioning methods to get the view: left, right, top, bottom.

d(A).left(B), selects B on the left side of A.
d(A).right(B), selects B on the right side of A.
d(A).up(B), selects B above A.
d(A).down(B), selects B under A.
So for above cases, we can alternatively select it with:

select “switch” on the right side of “Wi‑Fi”

d(text=“Wi‑Fi”).right(className=“android.widget.Switch”).click()
Multiple instances

Sometimes the screen may contain multiple views with the same properties, e.g. text, then you will have to use the “instance” property in the selector to pick one of qualifying instances, like below:

d(text=“Add new”, instance=0) # which means the first instance with text “Add new”
In addition, uiautomator2 provides a list-like API (similar to jQuery):

get the count of views with text “Add new” on current screen

d(text=“Add new”).count

same as count property

len(d(text=“Add new”))

get the instance via index

d(text=“Add new”)[0]
d(text=“Add new”)[1]

iterator

for view in d(text=“Add new”):
view.info # …
Notes: when using selectors in a code block that walk through the result list, you must ensure that the UI elements on the screen keep unchanged. Otherwise, when Element-Not-Found error could occur when iterating through the list.

Get the selected ui object status and its information
Check if the specific UI object exists

d(text=“Settings”).exists # True if exists, else False
d.exists(text=“Settings”) # alias of above property.

advanced usage

d(text=“Settings”).exists(timeout=3) # wait Settings appear in 3s, same as .wait(3)
Retrieve the info of the specific UI object

d(text=“Settings”).info
Below is a possible output:

{ u’contentDescription’: u’’,
u’checked’: False,
u’scrollable’: False,
u’text’: u’Settings’,
u’packageName’: u’com.android.launcher’,
u’selected’: False,
u’enabled’: True,
u’bounds’: {u’top’: 385,
u’right’: 360,
u’bottom’: 585,
u’left’: 200},
u’className’: u’android.widget.TextView’,
u’focused’: False,
u’focusable’: True,
u’clickable’: True,
u’chileCount’: 0,
u’longClickable’: True,
u’visibleBounds’: {u’top’: 385,
u’right’: 360,
u’bottom’: 585,
u’left’: 200},
u’checkable’: False
}
Get/Set/Clear text of an editable field (e.g., EditText widgets)

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
Get Widget center point

x, y = d(text=“Settings”).center()

x, y = d(text=“Settings”).center(offset=(0, 0)) # left-top x, y

Perform the click action on the selected UI object
Perform click on the specific object

click on the center of the specific ui object

d(text=“Settings”).click()

wait element to appear for at most 10 seconds and then click

d(text=“Settings”).click(timeout=10)

click with offset(x_offset, y_offset)

click_x = x_offset * width + x_left_top

click_y = y_offset * height + y_left_top

d(text=“Settings”).click(offset=(0.5, 0.5)) # Default center
d(text=“Settings”).click(offset=(0, 0)) # click left-top
d(text=“Settings”).click(offset=(1, 1)) # click right-bottom

click when exists in 10s, default timeout 0s

clicked = d(text=‘Skip’).click_exists(timeout=10.0)

click until element gone, return bool

is_gone = d(text=“Skip”).click_gone(maxretry=10, interval=1.0) # maxretry default 10, interval default 1.0
Perform long click on the specific UI object

long click on the center of the specific UI object

d(text=“Settings”).long_click()
Gesture actions for the specific UI object
Drag the UI object towards another point or another UI object

notes : drag can not be used for Android<4.3.

drag the UI object to a screen point (x, y), in 0.5 second

d(text=“Settings”).drag_to(x, y, duration=0.5)

drag the UI object to (the center position of) another UI object, in 0.25 second

d(text=“Settings”).drag_to(text=“Clock”, duration=0.25)
Swipe from the center of the UI object to its edge

Swipe supports 4 directions:

left
right
top
bottom
d(text=“Settings”).swipe(“right”)
d(text=“Settings”).swipe(“left”, steps=10)
d(text=“Settings”).swipe(“up”, steps=20) # 1 steps is about 5ms, so 20 steps is about 0.1s
d(text=“Settings”).swipe(“down”, steps=20)
Two-point gesture from one point to another

d(text=“Settings”).gesture((sx1, sy1), (sx2, sy2), (ex1, ey1), (ex2, ey2))
Two-point gesture on the specific UI object

Supports two gestures:

In, from edge to center
Out, from center to edge

notes : pinch can not be set until Android 4.3.

from edge to center. here is “In” not “in”

d(text=“Settings”).pinch_in(percent=100, steps=10)

from center to edge

d(text=“Settings”).pinch_out()
Wait until the specific UI appears or disappears

wait until the ui object appears

d(text=“Settings”).wait(timeout=3.0) # return bool

wait until the ui object gone

d(text=“Settings”).wait_gone(timeout=1.0)
The default timeout is 20s. see global settings for more details

Perform fling on the specific ui object(scrollable)

Possible properties:

horiz or vert
forward or backward or toBeginning or toEnd

fling forward(default) vertically(default)

d(scrollable=True).fling()

fling forward horizontally

d(scrollable=True).fling.horiz.forward()

fling backward vertically

d(scrollable=True).fling.vert.backward()

fling to beginning horizontally

d(scrollable=True).fling.horiz.toBeginning(max_swipes=1000)

fling to end vertically

d(scrollable=True).fling.toEnd()
Perform scroll on the specific ui object(scrollable)

Possible properties:

horiz or vert
forward or backward or toBeginning or toEnd, or to

scroll forward(default) vertically(default)

d(scrollable=True).scroll(steps=10)

scroll forward horizontally

d(scrollable=True).scroll.horiz.forward(steps=100)

scroll backward vertically

d(scrollable=True).scroll.vert.backward()

scroll to beginning horizontally

d(scrollable=True).scroll.horiz.toBeginning(steps=100, max_swipes=1000)

scroll to end vertically

d(scrollable=True).scroll.toEnd()

scroll forward vertically until specific ui object appears

d(scrollable=True).scroll.to(text=“Security”)
Watcher
You can register watchers to perform some actions when a selector does not find a match.

Register Watcher

When a selector can not find a match, uiautomator2 will run all registered watchers.

Click target when conditions match
d.watcher(“AUTO_FC_WHEN_ANR”).when(text=“ANR”).when(text=“Wait”)
.click(text=“Force Close”)

d.watcher(name) ## creates a new named watcher.

.when(condition) ## the UiSelector condition of the watcher.

.click(target) ## perform click action on the target UiSelector.

There is also a trick about click. You can use click without arguments.

d.watcher(“ALERT”).when(text=“OK”).click()

Same as

d.watcher(“ALERT”).when(text=“OK”).click(text=“OK”)
Press key when a condition becomes true
d.watcher(“AUTO_FC_WHEN_ANR”).when(text=“ANR”).when(text=“Wait”)
.press(“back”, “home”)

d.watcher(name) ## creates a new named watcher.

.when(condition) ## the UiSelector condition of the watcher.

.press(, …, .() ## press keys one by one in sequence.

Check if the named watcher triggered

A watcher is triggered, which means the watcher was run and all its conditions matched.

d.watcher(“watcher_name”).triggered

true in case of the specified watcher triggered, else false

Remove a named watcher

remove the watcher

d.watcher(“watcher_name”).remove()
List all watchers

d.watchers

a list of all registered watchers

Check for any triggered watcher

d.watchers.triggered

true in case of any watcher triggered

Reset all triggered watchers

reset all triggered watchers, after that, d.watchers.triggered will be false.

d.watchers.reset()
Remove watchers

remove all registered watchers

d.watchers.remove()

remove the named watcher, same as d.watcher(“watcher_name”).remove()

d.watchers.remove(“watcher_name”)
Force to run all watchers

force to run all registered watchers

d.watchers.run()
Run all watchers when page update. (因为稳定性原因,目前已废弃)

另外文档还是有很多没有写,推荐直接去看源码init.py

Global settings

set delay 1.5s after each UI click and click

d.click_post_delay = 1.5 # default no delay

set default element wait timeout (seconds)

d.wait_timeout = 30.0 # default 20.0
UiAutomator中的超时设置(隐藏方法)

d.jsonrpc.getConfigurator()
{‘actionAcknowledgmentTimeout’: 500,
‘keyInjectionDelay’: 0,
‘scrollAcknowledgmentTimeout’: 200,
‘waitForIdleTimeout’: 0,
‘waitForSelectorTimeout’: 0}

d.jsonrpc.setConfigurator({“waitForIdleTimeout”: 100})
{‘actionAcknowledgmentTimeout’: 500,
‘keyInjectionDelay’: 0,
‘scrollAcknowledgmentTimeout’: 200,
‘waitForIdleTimeout’: 100,
‘waitForSelectorTimeout’: 0}
为了防止客户端程序响应超时,waitForIdleTimeout和waitForSelectorTimeout目前已改为0

Refs: Google uiautomator Configurator

Input method
这种方法通常用于不知道控件的情况下的输入。第一步需要切换输入法,然后发送adb广播命令,具体使用方法如下

d.set_fastinput_ime(True) # 切换成FastInputIME输入法
d.send_keys(“你好123abcEFG”) # adb广播输入
d.clear_text() # 清除输入框所有内容(Require android-uiautomator.apk version >= 1.0.7)
d.set_fastinput_ime(False) # 切换成正常的输入法
d.send_action(“search”) # 模拟输入法的搜索
send_action 说明

该函数可以使用的参数有 go search send next done previous

什么时候该使用这个函数呢?

有些时候在EditText中输入完内容之后,调用press(“search”) or press(“enter”)发现并没有什么反应。 这个时候就需要send_action函数了,这里用到了只有输入法才能用的IME_ACTION_CODE。 send_action先broadcast命令发送给输入法操作IME_ACTION_CODE,由输入法完成后续跟EditText的通信。(原理我不太清楚,有了解的,提issue告诉我)

Toast
Show Toast

d.toast.show(“Hello world”)
d.toast.show(“Hello world”, 1.0) # show for 1.0s, default 1.0s
Get Toast

[Args]

5.0: max wait timeout. Default 10.0

10.0: cache time. return cache toast if already toast already show up in recent 10 seconds. Default 10.0 (Maybe change in the furture)

“default message”: return if no toast finally get. Default None

d.toast.get_message(5.0, 10.0, “default message”)

common usage

assert “Short message” in d.toast.get_message(5.0, default="")

clear cached toast

d.toast.reset()

Now d.toast.get_message(0) is None

XPath
For example: 其中一个节点的内容

<android.widget.TextView
index=“2”
text=“05:19”
resource-id=“com.netease.cloudmusic:id/qf”
package=“com.netease.cloudmusic”
content-desc=""
checkable=“false” checked=“false” clickable=“false” enabled=“true” focusable=“false” focused=“false”
scrollable=“false” long-clickable=“false” password=“false” selected=“false” visible-to-user=“true”
bounds="[957,1602][1020,1636]" />
xpath定位和使用方法

有些属性的名字有修改需要注意

description -> content-desc
resourceId -> resource-id
常见用法

wait exists 10s

d.xpath("//android.widget.TextView").wait(10.0)

find and click

d.xpath("//*[@content-desc=‘分享’]").click()

check exists

if d.xpath("//android.widget.TextView[contains(@text, ‘Se’)]").exists:
print(“exists”)

get all text-view text, attrib and center point

for elem in d.xpath("//android.widget.TextView").all():
print(“Text:”, elem.text)
# Dictionary eg:
# {‘index’: ‘1’, ‘text’: ‘999+’, ‘resource-id’: ‘com.netease.cloudmusic:id/qb’, ‘package’: ‘com.netease.cloudmusic’, ‘content-desc’: ‘’, ‘checkable’: ‘false’, ‘checked’: ‘false’, ‘clickable’: ‘false’, ‘enabled’: ‘true’, ‘focusable’: ‘false’, ‘focused’: ‘false’,‘scrollable’: ‘false’, ‘long-clickable’: ‘false’, ‘password’: ‘false’, ‘selected’: ‘false’, ‘visible-to-user’: ‘true’, ‘bounds’: ‘[661,1444][718,1478]’}
print(“Attrib:”, elem.attrib)
# Coordinate eg: (100, 200)
print(“Position:”, elem.center())
其他XPath常见用法

See also: https://github.com/openatx/uiautomator2/blob/master/uiautomator2/ext/xpath/README.md

常见问题
很多没写在这个地方的,都放到了这里 Common Issues

Stop UiAutomator
停止UiAutomator守护服务

https://github.com/openatx/uiautomator2/wiki/Common-issues

因为有atx-agent的存在,Uiautomator会被一直守护着,如果退出了就会被重新启动起来。但是Uiautomator又是霸道的,一旦它在运行,手机上的辅助功能、电脑上的uiautomatorviewer 就都不能用了,除非关掉该框架本身的uiautomator。下面就说下两种关闭方法

方法1:

直接打开uiautomator app(init成功后,就会安装上的),点击关闭UIAutomator

方法2:

d.service(“uiautomator”).stop()

d.service(“uiautomator”).start() # 启动

d.service(“uiautomator”).running() # 是否在运行

ATX与Maxim共存AccessibilityService的方法

项目历史
项目重构自 https://github.com/xiaocong/uiautomator
Google uiautomator与uiautomator2的区别
API相似但是不完全兼容
uiautomator2是安卓项目,而uiautomator是Java项目
uiautomator2可以输入中文,而uiautomator的Java工程需借助utf7输入法才能输入中文
uiautomator2必须明确EditText框才能向里面输入文字,uiautomator直接指定父类也可以在子类中输入文字
uiautomator2获取控件速度比uiautomator快
CHANGELOG (generated by pbr)
重大更新

1.0.0

移除 d.watchers.watched (会拖慢自动化的执行速度并且还会降低稳定性)

依赖项目
uiautomator守护程序 https://github.com/openatx/atx-agent
uiautomator jsonrpc serverhttps://github.com/openatx/android-uiautomator-server/
Contributors
codeskyblue (@codeskyblue)
Xiaocong He (@xiaocong)
Yuanyuan Zou (@yuanyuan)
Qian Jin (@QianJin2013)
Xu Jingjie (@xiscoxu)
Xia Mingyuan (@mingyuan-xia)
Artem Iglikov, Google Inc. (@artikz)
Other contributors

其他优秀的项目
google/mobly 谷歌内部的测试框架,虽然我不太懂,但是感觉很好用
https://www.appetizer.io/ 包含一个很好用的IDE,快速编写脚本,也可以插桩采集性能。
https://github.com/atinfo/awesome-test-automation 所有优秀测试框架的集合,包罗万象
http://www.sikulix.com/ 基于图像识别的自动化测试框架,非常的老牌
http://airtest.netease.com/ 本项目的前身,后来被网易广州团队接手并继续优化。实现有一个不错的IDE
LICENSE
MIT

uiautomator2使用教程相关推荐

  1. python UIAutomator2使用教程

    一.环境要求 python 3.6+ android 4.4+ 二.介绍 uiautomator2 是一个可以使用Python对Android设备进行UI自动化的库.其底层基于Google uiaut ...

  2. 2022软件测试技能 APP自动化测试 Python+Appium+Uiautomator2 实战教程

    系列文章目录 提示:阅读本章之前,请先阅读目录 文章目录 系列文章目录 前言 一.Appium 原理 二.环境搭建,一键搞定 1. 安装Java JDK 2. Android SDK 安装与配置 3. ...

  3. 安卓手机 Python 自动化测试

    其他自动化工具或者框架: Airtest:https://airtest.readthedocs.io/zh_CN/latest/ autojs:Auto.js快速入门实战教程:https://zhu ...

  4. UIautomator自动化平台搭建及使用

    自动化管理平台操作手册: APP元素定位法(实时): 1.下载元素定位安装包:pip install -U uiautomator2 pip install -U uiautomator2 -i ht ...

  5. python3 爬虫实战 :用 Appium 抓取手机 app 微信朋友圈的数据

    From:https://blog.csdn.net/Fan_shui/article/details/81413595 本编教程从 appium 的环境配置开始,到抓取手机 app 微信朋友圈结束. ...

  6. UIAutomator2的使用教程

    文章目录 一.简介 二.支持平台及语言 三.工作原理 四.安装 4.1 环境要求 4.2 安装adb 4.3 安装uiautomator2 4.4 设备安装atx-agent 4.5 安装wedito ...

  7. Python UIAutomator2 环境搭建教程

    说明 UIAutomator2可用于做安卓相关的自动化,WEditor可以使我们更加便捷的写自动化脚本 基础环境 Python 3.7.3 安卓手机  安卓8 开始搭建 如果使用conda ,请先创建 ...

  8. openpyxl安装_自拍教程76Python 一键批量安装第三方包

    案例故事: 在测试环境搭建环节,尤其是需要在新的电脑上搭建Python测试环境时, 可以考虑把日常自动化测试所需要用到的第三方Python包(非自带内置包), 一次性批量安装上. 准备阶段 1.确保p ...

  9. PHP 不跳转界面取input值进行验证_【Python】tesseract+uiautomator2+夜神模拟器 悠长假期手游集市识别验证码自动购买 - Amorius...

    开宗明义:这篇文章实际上就是把我的操作记录一遍,以防以后忘记了,又要到处去搜罗.由于我是个python小白,所以这些操作都是各处学来拼到一起的,也因此我确信如果不赶紧记下来,很快就会忘掉.于是就趁热写 ...

最新文章

  1. 来自程序员的福利!用Python做一款翻译软件
  2. Python 线程池 ThreadPoolExecutor(一) - Python零基础入门教程
  3. 故宫首开夜场门票秒空官网崩溃:7本书让网站挺住
  4. 学习笔记(02):MySQL数据库运维与管理-03-状态变量及查看方法
  5. 台式电脑cpu排行榜_微星新款游戏台式电脑亮相 配备英特尔第十代CPU
  6. 时间对象与字符串对象之间相互转换
  7. BestCoder Round #70
  8. 基于ssm的医院管理系统-医院门诊收费系统设计-医院住院系统代码
  9. 用PPT就可以做印章?是的,超简单超逼真,教你一分钟搞定
  10. 普通用户sudo echo权限依旧写入不了文件
  11. 10GE DWDM SFP+彩色光模块应用案例
  12. 有赞订单搜索AKF架构演进之路
  13. 6、编写应用程序,计算两个非零正整数的最大公约数和最小公倍数,要求两个非零正整数从键盘输入。
  14. Python Numpy数组的降序排列 由大到小
  15. 小米手机v3.exo 合并_eXo Platform 3.0访谈
  16. 【python】画玫瑰花喽!!!
  17. 计算机毕业设计springboot基于疫情背景下的新型点餐送餐系统bpe1s源码+系统+程序+lw文档+部署
  18. E. Xenon's Attack on the Gangs,Codeforces Round #614 (Div. 2),树形dp
  19. 内存存放方式_如何以正确的方式存放剩余涂料
  20. c++程序 cpu占用过高排查方法

热门文章

  1. 大学物理 复习指导、公式推导精简过程、结论归纳 第一章 质点运动学
  2. python提取文件中特定字符串
  3. DHCP自动分配IP
  4. HackerRank Nested Lists
  5. 麒麟V10服务器SP1安装教程步骤
  6. Springboot毕设项目考勤打卡系统 k0e7rjava+VUE+Mybatis+Maven+Mysql+sprnig)
  7. 产品or研发or网络安全
  8. 出队列c语言程序,队列的c语言实现
  9. 生成器模式 - Unity
  10. 一次尝试绕过ClassLoader双亲委派的实验