[python学习篇] uiautomator xiaocong
| docs/img | update screenshot | 4 years ago | |
| test | Merge pull request #123 from ericvalente/develop | 2 years ago | |
| uiautomator | update apk | 5 months ago | |
| .gitignore | add jar files | 3 years ago | |
| .travis.yml | add python 3.4 | 3 years ago | |
| LICENSE | change license to MIT | 4 years ago | |
| MANIFEST.in | modify d().info Nullpointer exception | 2 years ago | |
| NOTICE | rewrite some method. | 4 years ago | |
| README.md | update readme | 5 months ago | |
| requirements.txt | update .travis.yml | 4 years ago | |
| setup.cfg | update setup | 2 years ago | |
| setup.py | update apk | 5 months ago | |
| tox.ini | update tox init | 3 years ago |
README.md
uiautomator
This module is a Python wrapper of Android uiautomator testing framework. It works on Android 4.1+ simply with Android device attached via adb, no need to install anything on Android device.
from uiautomator import device as d d.screen.on()
d(text="Clock").click()
Installation
$ pip install uiautomator
Pre-requirements
- Install Android SDK, and set
ANDROID_HOMEenvironment to the correct path. - Enable ADB setting on device and connect your android device using usb with your PC.
- Allow apps to install from unknown sources on device settings.
import uiautomator
If
ANDROID_SERIALis defined in environment, or there is only one device connected:from uiautomator import device as d
Speficy the serial number when retrieving the device object
from uiautomator import Device d = Device('014E05DE0F02000E')Speficy the adb server host and port running on other computer
Although adb supports
-aoption since SDK 4.3, but now it has a bug on it. The only way to start adb server listenning on all interfaces instead of localhost, isadb -a -P 5037 fork-server server &from uiautomator import Device d = Device('014E05DE0F02000E', adb_server_host='192.168.1.68', adb_server_port=5037)
Notes: In below examples, we use d represent the android device object.
Table of Contents
- How to selector the Child and sibling UI object
- Get the specific UI object status and its information
- Perform the click action on the seleted UI object
- Gesture action for the specific ui object
Basic API Usages
This part show the normal actions of the device through some simple examples.
Retrieve the device info
d.info
Below is a possible result:
{ 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
}
Key Event Actions of the device
Turn on/off screen
# Turn on screen
d.screen.on()
# Turn off screen
d.screen.off()Alternative method is:
# wakeup the device
d.wakeup()
# sleep the device, same as turning off the screen.
d.sleep()Check if the screen is on or off
if d.screen == "on": # of d.screen != "off"
# do something in case of screen on
pass
if d.screen == "off": # of d.screen != "on"
# do something in case of screen off
passPress hard/soft key
# press home key
d.press.home()
# press back key
d.press.back()
# the normal way to press back key
d.press("back")
# press keycode 0x07('0') with META ALT(0x02) on
d.press(0x07, 0x02)Next keys are currently supported:
homebackleftrightupdowncentermenusearchenterdelete(ordel)recent(recent apps)volume_upvolume_downvolume_mutecamerapower
You can find all key code definitions at Android KeyEvent.
Gesture interaction of the device
Click the screen
# click (x, y) on screen
d.click(x, y)Long click the screen
# long click (x, y) on screen
d.long_click(x, y)Swipe
# swipe from (sx, sy) to (ex, ey)
d.swipe(sx, sy, ex, ey)
# swipe from (sx, sy) to (ex, ey) with 10 steps
d.swipe(sx, sy, ex, ey, steps=10)Drag
# drag from (sx, sy) to (ex, ey)
d.drag(sx, sy, ex, ey)
# drag from (sx, sy) to (ex, ey) with 10 steps
d.drag(sx, sy, ex, ey, steps=10)
Screen Actions of the device
Retrieve/Set Orientation
The possible orientation is:
naturalornleftorlrightorrupsidedownoru(can not be set)
# retrieve orientation, it may be "natural" or "left" or "right" or "upsidedown"
orientation = d.orientation
# set orientation and freeze rotation.
# notes: "upsidedown" can not be set until Android 4.3.
d.orientation = "l" # or "left"
d.orientation = "r" # or "right"
d.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 local file "home.png", can not work until Android 4.2.
d.screenshot("home.png")Dump Window Hierarchy
# dump the widown hierarchy and save to local file "hierarchy.xml"
d.dump("hierarchy.xml")
# or get the dumped content(unicode) from return.
xml = d.dump()Open notification or quick settings
# open notification, can not work until Android 4.3.
d.open.notification()
# open quick settings, can not work until Android 4.3.
d.open.quick_settings()Wait for idle or window update
# wait for current window to idle
d.wait.idle()
# wait until window update event occurs
d.wait.update()
Watcher
You can register watcher to perform some actions when a selector can not find a match.
Register Watcher
When a selector can not find a match, uiautomator 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 conditions match
d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
.press.back.home()
# Alternative way to define it as below
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.
# Alternavie way defining key sequence is press(<keybname>, ..., <keyname>)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 falseRemove named watcher
# remove the watcher
d.watcher("watcher_name").remove()List all watchers
d.watchers
# a list of all registered wachers' namesCheck if there is any watcher triggered
d.watchers.triggered
# true in case of any watcher triggeredReset all triggered watchers
# reset all triggered watchers, after that, d.watchers.triggered will be false.
d.watchers.reset()Remvoe 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()
Handler
The functionality of handler is same as Watcher, except it is implemented ourside of Android uiautomator. The most different usage between handler and watcher is, handler can use customized callback function.
def fc_close(device):
if device(text='Force Close').exists:
device(text='Force Close').click()
return True # return True means to break the loop of handler callback functions. # turn on the handler callback function
d.handlers.on(fc_close) # turn off the handler callback function
d.handlers.off(fc_close)
Selector
Selector is to identify specific ui object in current window.
# To seleted the object ,text is '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,textStartsWithclassName,classNameMatchesdescription,descriptionContains,descriptionMatches,descriptionStartsWithcheckable,checked,clickable,longClickablescrollable,enabled,focusable,focused,selectedpackageName,packageNameMatchesresourceId,resourceIdMatchesindex,instance
Child and sibling UI object
child
# get the child or grandchild
d(className="android.widget.ListView").child(text="Bluetooth")sibling
# get sibling or child of sibling
d(text="Google").sibling(className="android.widget.ImageView")child by text or description or instance
# get the child match className="android.widget.LinearLayout"
# and also it or its child or grandchild contains text "Bluetooth"
d(className="android.widget.ListView", resourceId="android:id/list") \
.child_by_text("Bluetooth", className="android.widget.LinearLayout") # allow scroll search to get the child
d(className="android.widget.ListView", resourceId="android:id/list") \
.child_by_text(
"Bluetooth",
allow_scroll_search=True,
className="android.widget.LinearLayout"
)child_by_descriptionis to find child which or which's grandchild contains the specified description, others are the same aschild_by_text.child_by_instanceis to find child which 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>
<node index="2" text="ON" resource-id="com.android.settings:id/switchWidget" class="android.widget.Switch" .../>
</node>
...
</node>We want to click the switch at the right side of text 'Wi‑Fi' to turn on/of Wi‑Fi. As there are several switches with almost the same properties, so we can not use like
d(className="android.widget.Switch")to select the ui object. Instead, we can use code below to select it.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 position
Also we can use the relative position methods to get the view:
left,right,top,bottom.d(A).left(B), means selecting B on the left side of A.d(A).right(B), means selecting B on the right side of A.d(A).up(B), means selecting B above A.d(A).down(B), means selecting B under A.
So for above case, we can write code alternatively:
## 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 e.g. text, then you will have to use "instance" properties in selector like below:
d(text="Add new", instance=0) # which means the first instance with text "Add new"
However, uiautomator provides list like methods to use it.
# 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 you are using selector like a list, you must make sure the screen keep unchanged, else you may get ui not found error.
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.Retrieve the info of the specific ui object
d(text="Settings").info
Below is a possible result:
{ 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
}
Set/Clear text of editable field
d(text="Settings").clear_text() # clear the text
d(text="Settings").set_text("My text...") # set the text
Perform the click action on the seleted ui object
Perform click on the specific ui object
# click on the center of the specific ui object
d(text="Settings").click()
# click on the bottomright corner of the specific ui object
d(text="Settings").click.bottomright()
# click on the topleft corner of the specific ui object
d(text="Settings").click.topleft()
# click and wait until the new window update
d(text="Settings").click.wait()Perform long click on the specific ui object
# long click on the center of the specific ui object
d(text="Settings").long_click()
# long click on the bottomright corner of the specific ui object
d(text="Settings").long_click.bottomright()
# long click on the topleft corner of the specific ui object
d(text="Settings").long_click.topleft()
Gesture action for the specific ui object
Drag the ui object to another point or ui object
# notes : drag can not be set until Android 4.3.
# drag the ui object to point (x, y)
d(text="Settings").drag.to(x, y, steps=100)
# drag the ui object to another ui object(center)
d(text="Settings").drag.to(text="Clock", steps=50)Swipe from the center of the ui object to its edge
Swipe supports 4 directions:
leftrighttopbottom
d(text="Settings").swipe.right()
d(text="Settings").swipe.left(steps=10)
d(text="Settings").swipe.up(steps=10)
d(text="Settings").swipe.down()Two point gesture from one point to another
d(text="Settings").gesture((sx1, sy1), (sx2, sy2)) \
.to((ex1, ey1), (ex2, ey2))Two point gesture on the specific ui object
Supports two gestures:
In, from edge to centerOut, 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()3 point gesture
d().gestureM((sx1, sy1), (sx2, sy2),(sx3, sy3)) \
.to((ex1, ey1), (ex2, ey2),(ex3,ey3))
d().gestureM((100,200),(300,200),(600,200),(100,600),(300,600),(600,900))Wait until the specific ui object appears or gone
# wait until the ui object appears
d(text="Settings").wait.exists(timeout=3000)
# wait until the ui object gone
d(text="Settings").wait.gone(timeout=1000)Perform fling on the specific ui object(scrollable)
Possible properties:
horizorvertforwardorbackwardortoBeginningortoEnd
# fling forward(default) vertically(default)
d(scrollable=True).fling()
# fling forward horizentally
d(scrollable=True).fling.horiz.forward()
# fling backward vertically
d(scrollable=True).fling.vert.backward()
# fling to beginning horizentally
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:
horizorvertforwardorbackwardortoBeginningortoEnd, orto
# scroll forward(default) vertically(default)
d(scrollable=True).scroll(steps=10)
# scroll forward horizentally
d(scrollable=True).scroll.horiz.forward(steps=100)
# scroll backward vertically
d(scrollable=True).scroll.vert.backward()
# scroll to beginning horizentally
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")
Contribution
- Fork the repo, and clone to your computer.
- Checkout a new branch from
developbranch - Install requirements:
pip install -r requirements.txt - Make your changes, and update tests. Don't forget adding your name at the end of 'Contributors' section
- Pass all tests and your code must be covered:
tox. - Commit your changes and submit pull request to
developbranch.
Contributors
- Xiaocong He (@xiaocong)
- Yuanyuan Zou (@yuanyuan)
- Qian Jin (@QianJin2013)
- Xu Jingjie (@xiscoxu)
- Xia Mingyuan (@mingyuan-xia)
Issues & Discussion
If you have any bug reports or annoyances please report them to our issue tracker at github issues.
Notes
- Android uiautomator works on Android 4.1+, so before using it, make sure your device is Android4.1+.
- Some methods are only working on Android 4.2/4.3, so you'd better read detailed java documentation of uiautomatorbefore using it.
- The module uses uiautomator-jsonrpc-server as its daemon to communicate with devices.
- The module is only tested on python2.7/3.2/3.3/pypy.
FAQ
Could not start JSONRPC server:
raise IOError("RPC server not started!")It may be caused by network, device, or environment. So when you meet the issue, please follow below steps and try to manually start the JSONRPC server.
Follow steps at uiautomator-jsonrpc-server to start jsonrpc server.
Check if jsonrpc server is ok:
curl -d '{"jsonrpc":"2.0","method":"deviceInfo","id":1}' localhost:9008/jsonrpc/0
If you see message like
{"jsonrpc":"2.0","id":1,"result":{"currentPackageName":"android","displayHeight":1280,"displayRotation":0,"displaySizeDpX":0,"displaySizeDpY":0,"displayWidth":720,"productName":"falcon","sdkInt":17,"naturalOrientation":true}}, it means the server is up.
If you can manually start the jsonrpc server, but your script always meets
IOError("RPC server not started!"), please submit an issue at github issues.Error
httplib.BadStatusLine: ''JsonRPC server needs to access temp directory on device, but on some low tier devices, it may meet error during accessing temp files without SD-CARD attached. So if you met the error, please insert a SD-CARD and then try again.
License
MIT
[python学习篇] uiautomator xiaocong的更多相关文章
- [python学习篇][python工具使用篇][1] 编辑,设置等
1 添加sublime到环境变量 win +r ,输入sysdm.cpl, 在弹出的界面选择高级,选择环境变量,编辑path,添加sublime的安装目录(这是sublime的一种安装方式,另外一种安 ...
- [python学习篇][廖雪峰][1]高级特性--创建生成器 方法2 yield
def fib(max): n, a, b = 0, 0, 1 while n < max: print b a, b = b, a + b n = n + 1 将print b 改成yield ...
- [python学习篇][廖雪峰][1]高级特性--创建生成器 方法1 a = (x for x in range(1,3))
创建一个生成器的方法: for x in range(1,10000000) ,先生成一个列表[1........9999999] 如果我们只想要后面的几个元素,会发现浪费很多空间.所以,如果列表元素 ...
- [python学习篇][廖雪峰][1]高级特性 ---迭代
由于字符串也是可迭代对象,因此,也可以作用于for循环: >>> for ch in 'ABC': ... print ch ... A B C 所以,当我们使用for循环时,只要作 ...
- [python学习篇][书籍学习][python standrad library][内建函数]之[list,open,len,pow,range,
Python 解释器内置了一些函数,它们总是可用的.这里将它们按字母表顺序列出. Built-in Functions abs() divmod() input() open() st ...
- [python学习篇][书籍学习][python standrad library][内建函数]之[all,any,basestring,isinstance,bin,bool,@classmethod,@staticmethod,cmp,enumerate
Python 解释器内置了一些函数,它们总是可用的.这里将它们按字母表顺序列出. Built-in Functions abs() divmod() input() open() st ...
- [python学习篇][系统学习][1]python标准库中文、英文网址(一些内建函数,标准库都可以在这里查找)
http://docspy3zh.readthedocs.io/en/latest/library/ 半中文网址 http://usyiyi.cn/translate/python_278/lib ...
- [python学习篇][廖雪峰][4]函数--reduce
reduce的用法.reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是: reduce(f, ...
- [python学习篇][廖雪峰][2][高级函数] map 和reduce
我们先看map.map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回. 举例说明,比如我们有一个函数f(x)=x2,要把这个函数 ...
随机推荐
- NullPointerException检测
APET-NPE插件工作原理 android应用程序编译的过程如下: 从图中,我们可以看出,app编译大致经历了四大阶段:java source files -> .class files -& ...
- POJ 1651 Multiplication Puzzle (区间DP,经典)
题意: 给出一个序列,共n个正整数,要求将区间[2,n-1]全部删去,只剩下a[1]和a[n],也就是一共需要删除n-2个数字,但是每次只能删除一个数字,且会获得该数字与其旁边两个数字的积的分数,问最 ...
- 远程桌面连接(mstsc)无法断开的解决方案
某2008 r2有二个系统账户,同时允许两个tcp连接,但每个用户仅同时允许一人登录.不知何因,关闭远程桌面连接的窗口后,再次连接就瞬间提示无法被连接.查看了事件查看器,信息为被注销,这是因为设置了“ ...
- python爬虫之路——对字符串的处理
对字符串的处理分类:分段,连接,剔除,提取,综合 连接:+,* +(加法)的使用 a='i' b=' love' c=' you' print(a+b+c) #return i love you *( ...
- UVALive 4329 Ping pong (BIT)
枚举中间的人,只要知道在这个人前面的技能值比他小的人数和后面技能值比他小的人数就能计算方案数了,技能值大的可有小的推出. 因此可以利用树状数组,从左到右往树上插点,每个点询问sum(a[i]-1)就是 ...
- 在.net平台上运行伪JAVA
由于在一个项目局方要求使用JAVA平台, 而当前又都是.net平台的应用. 重新用JAVA开发工作量太大. 时间也来不及. 想到在.net中有url rewrite功能, 何不先"骗&quo ...
- PAT (Basic Level) Practise (中文)-1039. 到底买不买(20)
PAT (Basic Level) Practise (中文)-1039. 到底买不买(20) http://www.patest.cn/contests/pat-b-practise/1039 小红 ...
- JQuery EasyUI学习记录(二)
1.jquery easyUI动态添加选项卡(查看jquery easyUI手册) 1.1 用于动态添加一个选项卡 1.1.1 选中指定的选项卡和判断某个选项卡是否存在 测试代码: <a id= ...
- ReactiveCocoa入门-part2
ReactiveCocoa是一个框架,它能让你在iOS应用中使用函数响应式编程(FRP)技术.在本系列教程的第一部分中,你学到了如何将标准的动作与事件处理逻辑替换为发送事件流的信号.你还学到了如何转换 ...
- webpack开始一个项目的步骤
这几天在学习Vue 用到了webpack打包工具 开始一个项目的时候 需要配置很多项 刚开始写的时候 配置文件总是缺什么再去配置什么 创建项目就用了半个小时 后来觉得应该有个步骤 这样 ...