uiautomator2
uiautomator2
- 设备和开发机可以脱离数据线,通过WiFi互联(基于atx-agent)
- 集成了openstf/minicap加快截图速度
- 集成了openstf/minitouch达到精确实时控制设备
- 修复了xiaocong/uiautomator经常性退出的问题
- 代码进行了重构和精简,方便维护
Installation
- Install uiautomator2# Since uiautomator2 is still under development, you have to add --pre to install the development versionpip install --pre uiautomator2# Or you can install directly from github sourcegit clone https://github.com/openatx/uiautomator2pip install -e uiautomator2Optionally, pillow is needed to process screenshot data.pip install pillow
- Deploy associated daemons to a device 电脑连接上一个手机或多个手机, 确保adb已经添加到环境变量中,执行下面的命令会自动安装本库所需要的设备端程序:uiautomator-server 、atx-agent、openstf/minicap、openstf/minitouchpython -m uiautomator2 init安装提示success即可
Usage 使用指南
命令行使用
- init: 为设备安装所需要的程序
- install: 安装apk,apk通过URL给出$ python -m uiautomator2 install $device_iphttps://example.org/some.apkMainThread: 15:37:55,731 downloading 80.4 kB / 770.6 kBMainThread: 15:37:56,763 installing 770.6 kB / 770.6 kBMainThread: 15:37:58,780 success installed 770.6 kB / 770.6 kB
- clear-cache: 清空缓存$ python -m uiautomator2 clear-cache
- app-stop-all: 停止所有应用$ python -m uiautomator2 app-stop-all $device_ip
- screenshot: 截图$ python -m uiautomator2 screenshot $device_ip screenshot.jpg
QUICK START
- Through WiFi (recommended) Suppose device IP is 10.0.0.1 and your PC is in the same network. 通过WiFi(推荐)假设你的设备ip是10.0.0.1并且你的PC在同一个网络
- Through USB Suppose the device serial is 123456f (seen from adb devices) 通过USB连接,假设你的设备的序列号是123456f
一些常用但是不知道归到什么类里的函数
感觉肯定用得着的资料链接
- weditor 用于查看UI层次结构,方便写脚本用。
- htmlreport 记录测试过程的测试报告(实验性质)
检查并维持设备端守护进程处于运行状态
连接本地USB设备
一定时间内,出现则点击
如何停用UiAutomator的守护程序
打开调试开关
Table of Contents 目录
- Auto click permission dialogs 自动点击权限对话框
- Screen-related 屏幕相关的
App management
Install an app
Launch an app
Stop an app
Stop all running apps
Push and pull files
- push a file to the device# push to a folderd.push("foo.txt", "/sdcard/")# push and renamed.push("foo.txt", "/sdcard/bar.txt")# push fileobjwith open("foo.txt", 'rb') as f:d.push(f, "/sdcard/")# push and change file access moded.push("foo.sh", "/data/local/tmp/", mode=0o755)
- pull a file from the deviced.pull("/sdcard/tmp.txt", "tmp.txt")# FileNotFoundError will raise if the file is not found on the deviced.pull("/sdcard/some-file-not-exists.txt", "tmp.txt")
Auto click permission dialogs
- Open uiautomatorviewer.bat
- Get popup hierarchy
Basic API Usages
Shell commands
- Run a short-lived shell command with a timeout protection. (Default timeout 10 minutes)d.adb_shell('pwd')d.adb_shell('ls', '-l')d.adb_shell('ls -l')This returns a UTF-8 encoded string for stdout merged with stderr. Note for binary mode stdouts, the output is encoded as a UTF-8 string not a bytearray. If the command is a blocking command, adb_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 TODO: not implemented yetd.adb_shell_longrunning('getevent', '-lt')This API returns a generator.
Session
- Launch appsess = d.session("com.netease.cloudmusic") # start 网易云音乐
- Attach to the running appsess = d.session("com.netease.cloudmusic", attach=True)
- Detect app crash# When app is still runningsess(text="Music").click() # operation goes normal# If app crash or quitsess(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 futuresess.running() # True or False
Retrieve the device info
Key Events
- Turn on/off screend.screen_on() # turn on the screend.screen_off() # turn off the screen
- Get current screen statusd.info.get('screenOn') # require Android >= 4.4
- Press hard/soft keyd.press("home") # press the home key, with key named.press("back") # press the back key, with key named.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
- Unlock screend.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 screend.click(x, y)
- Long click on the screend.long_click(x, y)d.long_click(x, y, 0.5) # long click 0.5s (default)
- Swiped.swipe(sx, sy, ex, ey)d.swipe(sx, sy, ex, ey, 0.5) # swipe for 0.5s(default)
- Dragd.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 pointsd.swipe((x0, y0), (x1, y1), (x2, y2), 0.2)多用于九宫格解锁,提前获取到每个点的相对坐标(这里支持百分比), 更详细的使用参考这个帖子 使用u2实现九宫图案解锁
Screen-related
- Retrieve/Set device orientationThe 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 rotationd.freeze_rotation()# un-freeze rotationd.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 firstimage = d.screenshot()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 firstimport cv2image = d.screenshot(format='opencv')cv2.imwrite('home.jpg', image)
- Dump UI hierarchy# get the UI hierarchy dump content (unicoded).xml = d.dump_hierarchy()
- Open notification or quick settingsd.open_notification()d.open_quick_settings()
Selector
- 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 grandchildrend(className="android.widget.ListView").child(text="Bluetooth")
- siblings# get siblingsd(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 searchd(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.
- UiScrollable, getChildByDescription, getChildByText, getChildByInstance
- UiCollection, getChildByDescription, getChildByText, getChildByInstance
- <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><node index="2" text="ON" resource-id="com.android.settings:id/switchWidget" class="android.widget.Switch" .../></node>...</node>
- 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 positioningAlso 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.
- ## select "switch" on the right side of "Wi‑Fi"d(text="Wi‑Fi").right(className="android.widget.Switch").click()
- Multiple instancesSometimes 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 screend(text="Add new").count# same as count propertylen(d(text="Add new"))# get the instance via indexd(text="Add new")[0]d(text="Add new")[1]...# iteratorfor view in d(text="Add new"):view.info # ...Notes: when using selectors in a list fashion, 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 existsd(text="Settings").exists # True if exists, else Falsed.exists(text="Settings") # alias of above property.
- Retrieve the info of the specific UI objectd(text="Settings").infoBelow 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 textd(text="Settings").set_text("My text...") # set the textd(text="Settings").clear_text() # clear the text
Perform the click action on the selected UI object
- Perform click on the specific object# click on the center of the specific ui objectd(text="Settings").click()# wait element to appear for at most 10 seconds and then clickd(text="Settings").click(timeout=10)# alias of clickd(text="Settings").tap()
- Perform long click on the specific UI object# long click on the center of the specific UI objectd(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 secondd(text="Settings").drag_to(x, y, duration=0.5)# drag the UI object to (the center position of) another UI object, in 0.25 secondd(text="Settings").drag_to(text="Clock", duration=0.25)
- Two-point gesture from one point to anotherd(text="Settings").gesture((sx1, sy1), (sx2, sy2), (ex1, ey1), (ex2, ey2))
- Two-point gesture on the specific UI objectSupports 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 edged(text="Settings").pinch_out()
- Wait until the specific UI appears or disappears# wait until the ui object appearsd(text="Settings").wait(timeout=3.0) # return bool# wait until the ui object goned(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 horizontallyd(scrollable=True).fling.horiz.forward()# fling backward verticallyd(scrollable=True).fling.vert.backward()# fling to beginning horizontallyd(scrollable=True).fling.horiz.toBeginning(max_swipes=1000)# fling to end verticallyd(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 horizontallyd(scrollable=True).scroll.horiz.forward(steps=100)# scroll backward verticallyd(scrollable=True).scroll.vert.backward()# scroll to beginning horizontallyd(scrollable=True).scroll.horiz.toBeginning(steps=100, max_swipes=1000)# scroll to end verticallyd(scrollable=True).scroll.toEnd()# scroll forward vertically until specific ui object appearsd(scrollable=True).scroll.to(text="Security")
Watcher
- Register WatcherWhen 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.
- 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(<keyname>, ..., <keyname>.() ## press keys one by one in sequence.
- Check if the named watcher triggeredA 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 watcherd.watcher("watcher_name").remove()
- List all watchersd.watchers# a list of all registered watchers
- Check for any triggered watcherd.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 watchersd.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 watchersd.watchers.run()
Global settings
Input method
Toast
测试方法
Google uiautomator与uiautomator2的区别
- API相似但是不完全兼容
- uiautomator2是安卓项目,而uiautomator是Java项目
- uiautomator2可以输入中文,而uiautomator的Java工程需借助utf7输入法才能输入中文
- uiautomator2必须明确EditText框才能向里面输入文字,uiautomator直接指定父类也可以在子类中输入文字
- uiautomator2获取控件速度比uiautomator快
常见问题
- 提示502错误尝试手机连接PC,然后运行下面的命令adb shell am instrument -w -r -e debug false -e class com.github.uiautomator.stub.Stub \com.github.uiautomator.test/android.support.test.runner.AndroidJUnitRunner如果运行正常,启动测试之前增加一行代码d.healthcheck()
实验室功能
远程查看
手机USB连接后,自动调用init命令
项目历史
CHANGELOG (generated by pbr)
依赖项目
- 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)
LICENSE
uiautomator2的更多相关文章
- UiAutomator2.0升级填坑记
UiAutomator2.0升级填坑记 SkySeraph May. 28th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.sk ...
- UiAutomator2.0 - Toast信息的验证
目录 问题:在做UI自动化测试时,偶尔会碰到 Toast 这种提示信息(如图),通过Uiautomatorviewer 无法获该类控件的信息.所以无法验证,该条case不能实现.然后就没然后了... ...
- UiAutomator2.0 - 与AccessibilityService的关联
目录 一.Android中的 Accessibility 二.UiAutomator2.0 与 AccessibilityService 三.验证与 AccessibilityService的关联 A ...
- UiAutomator2.0 - 控件实现点击操作原理
目录 一.UiObject 二.UiObject2 穿梭各大技术博客网站,每天都能看到一些的新的技术.突然感觉UiAutomator 2.0相对于现在来说已经是个很久远的东西了ε=(´ο`*))).写 ...
- 两分钟搞懂UiAutomator、UiAutomator2、Bootstrap的关系
很多同学经过一段时间的学习之后都明白了Appium的基本原理,但是越学习到后面发现出现的很多陌生名词无法弄清楚其具体作用,今天这篇文章的目的就是为了让大家来弄懂三个高频名词:UiAutomator.U ...
- uiautomator2 使用Python测试 Android应用
GitHub地址:https://github.com/openatx/uiautomator2 介绍 uiautomator2 是一个可以使用Python对Android设备进行UI自动化的库.其底 ...
- UiAutomator1.0 与 UiAutomator2.0
在使用2.0之前,对android自动化框架也做过一些了解<Android 自动化测试框架>.使用UiAutomator2.0也有一段时间,这里将1.0与2.0进行一个对比总结. Ui ...
- 使用uiautomator2进行webview页面的测试
1.开发开启webview debug模式 2.使用VirtualXposed框架进行webview测试,详细见https://testerhome.com/topics/16156 下载,安装Vir ...
- 手机APP自动化之uiautomator2 +python3 UI自动化
题记: 之前一直用APPium直到用安卓9.0 发现uiautomatorviewer不支持安卓 9.0,点击截屏按钮 一直报错,百度很久解决方法都不可以,偶然间看见有人推荐:uiautomator ...
- uiautomator2 获取APP Toast内容
前言:appium必须是1.6以上的版本 环境(安装和安装都可以运行成功,我也不确定要不要这个): 1.抓到toast需要安装uiautomator2,安装npm:npm install -g cnp ...
随机推荐
- Vmware迁移以后eth0消失,无法上网
一个再普通不过的大神帮助小菜做虚拟机镜像的事情: 小张:帮我做个Vmware下的Ubuntu镜像吧,大神. 小黄:好啊,等我一下,下午发给你. 经过一番操作,小黄顺利的做出了一个虚拟机操作系统 小黄: ...
- js验证input输入正整数 和 输入的金额小数点后保留两位(PC端键盘输入)
// 验证开头不为零的正整数 WST.zhengZhengShuIn = function (className){ var rex = /^[1-9]{1}[0-9]*$/;//正整数 $(&quo ...
- macos修改vmware Fusion的NAT网络
https://blog.csdn.net/zhishengqianjun/article/details/77046796 http://pubs.vmware.com/fusion-5/index ...
- CentOS7下部署NTP Server
系统环境:CentOS Linux release 7.4.1708 (Core) 3.10.0-693.el7.x86_64 软件版本:chrony-3.1-2.el7.centos.x86_64 ...
- HTML5新协议介绍 WebSocket
WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站为了实现即时通讯(real-time) ...
- This page contains the following error
解决办法:将header头注释掉 header("content-type:text/xml; charset=UTF-8");
- gruop by报错this is incompatible with sql_mode=only_full_group_by
set @@GLOBAL.sql_mode=''; set sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_ ...
- dedecms的if标签、foreach标签
1.if标签 (1)下拉列表 <select name="prize_type[]" class="type J-prize-type" id=" ...
- Debian Buster Nginx 布署 Brophp 项目(类 Thinkphp)
1 材料 debian buster nginx a project that develop base brophp 2 步骤 配置文件 /etc/nginx/sites-available/pis ...
- 日期处理相关 - “Fri Dec 11 00:00:00 CST 2015”日期格式解析
1.后台处理方式: /* 精简版解析 - 推荐 */ String a= "Fri Dec 11 00:00:00 CST 2015"; Date d = new Date(a); ...