python +android +uiautomator test 在init中定义的方法
uiautomator
该模块是Android的一个Python包装uiautomator测试框架。它适用于Android 4.1+,只需通过adb连接Android设备,无需在Android设备上安装任何东西。
从 uiautomator 进口设备的 ð
d.screen.on()
D(id= “时钟”)。点击()
安装
$ pip install uiautomator
前提条件
- 安装Android的SDK,并设置
ANDROID_HOME
- 环境以正确的路径。
- 启用设备上的ADB设置,并使用USB连接您的Android设备与您的电脑。
导入uiautomator
- 如果
ANDROID_SERIAL
- 在环境中定义的,或只有一个连接的设备:
从 uiautomator 进口设备的 ð
- 检索设备对象时,限制序列号
从 uiautomator 进口设备
ð =设备(' 014E05DE0F02000E “)
- speficy在其他计算机上运行的adb服务器主机和端口
虽然亚行支持
-a
- 选项SDK 4.3以来,但现在它有一个bug。在所有接口而不是localhost上启动adb服务器侦听的唯一方法是
adb -a -P 5037 fork-server server &
从 uiautomator 进口设备
ð =设备(' 014E05DE0F02000E ',adb_server_host = “ 192.168.1.68 ”,adb_server_port = 5037)
注:在下面的例子中,我们使用d
代表Android设备对象。
目录
基本API用法
此部分通过一些简单的示例显示设备的正常操作。
- 检索设备信息
d.info
以下是可能的结果:
{ 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
}
关键事件设备的操作
- 打开/关闭屏幕
#在屏幕上打开
d.screen.on() #关闭屏幕
d.screen.off()
替代方法是:
#唤醒设备
d.wakeup() #睡眠设备,一样关闭屏幕。
d.sleep()
- 按硬/软键
#按home键
d.press.home() #按返回键
d.press.back() #正常的方式按返回键
d.press( “回”)
#按下键码0×07(0)与元ALT (0X02)上
d.press( 0x的 07, 0X 02)
- 目前支持下列键:
home
back
left
right
up
down
center
menu
search
enter
delete
- (或
del
- )
recent
- (最近的应用程式)
volume_up
volume_down
volume_mute
camera
power
你可以找到所有关键代码定义的Android的KeyEvent。
手势设备的交互
- 单击屏幕
#点击(X,Y)在屏幕上
d.click(X,Y)
- 长按屏幕
#长按(X,Y)在屏幕上
d.long_click(X,Y)
- 滑动
#从(SX,SY)轻扫(EX,EY)
d.swipe(SX,SY,EX,EY) #从(SX,SY)轻扫(EX,EY)与10个步骤
d.swipe(SX,SY ,前,安永,步骤= 10)
- 拖动
#从(SX,SY)拖动(EX,EY)
d.drag(SX,SY,EX,EY) #从(SX,SY)拖动(EX,EY)与10个步骤
d.drag(SX,SY ,前,安永,步骤= 10)
屏幕设备的操作
- 检索/设置方向
可能的方向是:
natural
- 要么
n
left
- 要么
l
right
- 要么
r
upsidedown
- 或
u
- (不能设定)
#检索方向,也可能是“天然”或“左”或“右”或“upsidedown”
方向 = d.orientation
#设置定向和冻结旋转。
#指出:“upsidedown”不能设置到Android 4.3的。
d.orientation = “升” #或“左”的
d.orientation = “ - [R ” #或“右”
d.orientation = “ ñ ” #或“自然”
- 冻结/取消冻结旋转
#冻结旋转
d.freeze_rotation() #取消冻结旋转
d.freeze_rotation(假)
- 截取屏幕截图
#采取截图并保存到本地文件“home.png”,直到Android 4.2或不能工作。
d.screenshot( “ home.png ”)
- 转储窗口层次结构
#转储widown层次结构并保存到本地文件“hierarchy.xml”
d.dump( “ hierarchy.xml ”)
#或获得回报倾倒内容(Unicode)的。
XML = d.dump()
- 打开通知或快速设置
#开放的通知,不能工作,直到Android 4.3的。
d.open.notification() #开启快速设定,不能工作,直到Android 4.3的。
d.open.quick_settings()
- 等待空闲或窗口更新
#等待当前窗口空闲
d.wait.idle() #等待,直到窗口更新事件发生
d.wait.update()
观察者
你可以注册守望者执行某些动作时,选择器不能找到匹配。
- 注册观察者
当选择器找不到匹配项时,uiautomator将运行所有注册的观察器。
- 条件匹配时点击目标
d.watcher( “ AUTO_FC_WHEN_ANR ”)。当(文= “ ANR ”)。当(文= “等待”)\
。点击(文字= “强制关闭”)
# d.watcher(名)##创建一个新的命名观察者。
# 。当(条件)##观察者的UiSelector条件。
# 。点击(目标)##执行对目标UiSelector点击动作。
- 条件匹配时按键
d.watcher( “ AUTO_FC_WHEN_ANR ”)。当(文= “ ANR ”)。当(文= “等待”)\
.press.back.home() #另类的方式来定义它,如下
d.watcher( “ AUTO_FC_WHEN_ANR ”)。当(文= “ ANR ”)。当(文= “等待”)\
。按(“回”,“家”)
# d.watcher(名)##创建一个新的名为守望。# 。当(条件)##观察者的UiSelector条件。# 。按<键名> ...... <键名>。()##按下按键逐个顺序。# Alternavie方式定义按键顺序是按(<keybname>,...,<键名>)
- 检查命名的监视器是否触发
触发观察者,这意味着观察者运行并且其所有条件都匹配。
d.watcher( “ watcher_name ”).triggered
#真在指定守望的情况下触发,否则为假
- 删除命名监视器
#删除观察者
d.watcher( “ watcher_name ”)上卸下摆臂()
- 列出所有观察者
d.watchers
#所有注册wachers'名称的列表
- 检查是否有任何观察者触发
d.watchers.triggered
# 真正的触发任何看守的情况下,
- 重置所有触发的观察者
#重置所有触发观察家,在那之后,d.watchers.triggered会是假的。
d.watchers.reset()
- Remvoe观察者
#删除所有已注册的观察家
d.watchers.remove() #删除指定的守望者一样,同样d.watcher(“watcher_name”)。remove()方法
d.watchers.remove( “ watcher_name ”)
- 强制运行所有观察者
#力量来运行所有注册的观察者
d.watchers.run()
处理程序
处理程序的功能与Watcher相同,只是它实现了我们的Android uiautomator。处理程序和观察程序之间最不同的用法是,处理程序可以使用自定义的回调函数。
高清 fc_close(设备):
如果设备(文= '强制关闭“).exists:
设备(文= '强制关闭”)。点击()
返回 真 #返回True手段打破处理程序回调函数的循环。
#在处理回调函数反过来
d.handlers.on(fc_close) #关闭句柄回调函数
d.handlers.off(fc_close)
选择器
选择器是标识当前窗口中的特定ui对象。
#要入围对象,文字是“时钟”和它的类名是“android.widget.TextView'
D(文= '时钟',的className = ' android.widget.TextView ')
选择器支持以下参数。请参阅UiSelector DOC java的详细信息。
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
子对象和同级UI对象
- 儿童
#得到孩子或孙子
D(的className = “ android.widget.ListView ”).child(文= “蓝牙”)
- 兄弟
#得到同胞的兄弟姐妹或子女
D(文= “谷歌”).sibling(的className = “ android.widget.ImageView ”)
- 子文本或描述或实例
#得到孩子匹配的className =“android.widget.LinearLayout”
#而且它或它的子女或孙子包含文本“蓝牙”
D(的className = “ android.widget.ListView ”, RESOURCEID = “机器人:ID /列表”) \
.child_by_text( “蓝牙”,的className = “ android.widget.LinearLayout ”)#允许滚动搜索,获得子
D(的className = “ android.widget.ListView ”, RESOURCEID = “机器人:ID /列表”)\
。 child_by_text( “蓝牙”,
allow_scroll_search = 真,
的className = “ android.widget.LinearLayout ”
)
child_by_description
- 是找到子哪个或哪些是孙子包含指定的描述中,其他是相同的
child_by_text
- 。
child_by_instance
- 是在其子层次结构中指定实例的任何位置找到具有子UI元素的子项。这是一个没有可见的意见进行滚动。
详情请参阅以下链接:
getChildByDescription
- ,
getChildByText
- ,
getChildByInstance
getChildByDescription
- ,
getChildByText
- ,
getChildByInstance
上面的方法支持链接调用,例如对于下层
< 节点 指数 = “ 0 ” 文本 = “ ” 资源ID = “机器人:ID /列表” 级 = “ android.widget.ListView ” ...>
< 节点 指数 = “ 0 ” 文本 = “ WIRELESS & NETWORKS ” 资源-id = “ ” 类 = “ android.widget.TextView ” ... />
< 节点 索引 = “ 1 ” 文本 = “ ” 资源ID = “ ” 类 = “ android.widget.LinearLayout ” ...>
< 节点 指数 = “ 1 ” 文本 = “ ” 资源ID = “ ” 级 = “ android.widget.RelativeLayout ” ...>
< 节点 指数 = “ 0 ” 文本 = “无线网络连接” 资源ID = “机器人: ID /标题“ 级 = ” android.widget.TextView “ ... />
</ 节点 >
< 节点 指数 = ” 2 “ 文本 = ” ON “ 资源ID = ” com.android.settings:ID / switchWidget “ 类 = “ android.widget.Switch ” ... />
</ 节点 >
...
</ 节点 >
我们要点击文本“Wi-Fi”右侧的开关打开/打开Wi-Fi。因为有几个开关,几乎相同的属性,所以我们不能使用类似d(className="android.widget.Switch")
选择的UI对象。相反,我们可以使用下面的代码来选择它。
D(的className = “ android.widget.ListView ”,RESOURCEID = “机器人:ID /列表”)\
.child_by_text( “无线网络连接”,的className = “ android.widget.LinearLayout ”)\
.child(的className = “机器人.widget.Switch “)\
。点击()
- 相对位置
此外,我们可以用相对位置的方法来获取视图:
left
- ,
right
- ,
top
- ,
bottom
- 。
d(A).left(B)
- ,意味着在左侧选择B。
d(A).right(B)
- ,表示选择A右侧的B.
d(A).up(B)
- ,表示选择B以上的A.
d(A).down(B)
- ,表示在A下选择B.
所以对于上面的情况,我们可以写代码:
##选择的“无线网络连接”右侧的“开关”
D(文= “无线网络连接”).right(的className = “ android.widget.Switch ”)。点击()
- 多个实例
有时,屏幕可能包含多个视图与相同的例如文本,那么你将不得不使用选择器中的“实例”属性,如下所示:
D(文= “新增”,比如= 0) #这意味着一审文本“新增”
但是,uiautomator提供了类似的方法来使用它。
#得到的文本意见的计当前屏幕上的“添加新的”
D(文= “新增”).Count之间#一样count属性LEN(D(文= “新增”)) #通过索引获取实例
ð (文= “新增”)[ 0 ]
D(文= “新增”)[ 1 ]
... #迭代器的视图中 D(文= “添加新”):
view.info # ...
注意:当您使用选择喜欢的列表,你必须确保屏幕保持不变,否则你可能会得到UI未找到错误。
获取所选的ui对象状态及其信息
- 检查特定ui对象是否存在
D(文= “设置”).exists #是否存在真,否则假
d.exists(文= “设置”)#以上财产的别名。
- 检索特定ui对象的信息
D(文= “设置”).INFO
以下是可能的结果:
{ 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
}
- 设置/清除可编辑字段的文本
D(文= “设置”).clear_text() #清除文字
D(文= “设置”).set_text( “我的文字...... ”) #设置文本
对选中的ui对象执行单击操作
- 点击特定的ui对象
#点击特定的UI对象的中心
D(文= “设置”)。单击()
#点击具体的UI对象的bottomright角落
D(文= “设置”)).click.bottomright(
#请点击具体的UI对象的左上边角
D(文= “设置”).click.topleft()
#点击等到新窗口更新
D(文= “设置”).click.wait()
- 长时间点击特定的ui对象
#长按一下特定的UI对象的中心
D(文= “设置”).long_click()
#长按具体的UI对象的bottomright角落
D(文= “设置”).long_click.bottomright()
#长按具体的UI对象的左上边角
D(文= “设置”).long_click.topleft()
针对特定ui对象的手势动作
- 将ui对象拖动到另一个点或ui对象
#注:拖不能设置到Android 4.3的。
#拖拽的UI对象,以点(X,Y)
D(文= “设置”).drag.to(X,Y,步骤= 100)
#拖拽的UI对象到另一个UI对象(中心),
D(文= “设置“).drag.to(文= ”时钟“,步骤= 50)
- 从ui对象的中央滑动到其边缘
滑动支持4个方向:
left
right
top
bottom
D(文= “设置”).swipe.right()
D(文= “设置”).swipe.left(步骤= 10),
D(文= “设置”).swipe.up(步骤= 10),
D(文字= “设置”).swipe.down()
- 两点手势从一个点到另一个点
D(文= “设置”).gesture((SX1,SY1),(SX2,SY2))\
。要((EX1,EY1),(EX2,EY2))
- 在特定ui对象的两点姿态
支持两种手势:
In
- ,从边到中心
Out
- ,从中心到边缘
#注:捏不能设置到Android 4.3的。
#从边缘到中心。这里是“在”不“,在”
D(文= “设置”).pinch.In(百分比= 100,步= 10)
#从中心到边缘
D(文= “设置”).pinch.Out()
- 等待特定ui对象出现或消失
#等到UI对象出现
D(文= “设置”).wait.exists(超时= 3000)
#等待,直到UI对象转眼
D(文= “设置”).wait.gone(超时= 1000)
- 对特定的ui对象执行fling(可滚动)
可能的属性:
horiz
- 要么
vert
forward
- 或
backward
- 或
toBeginning
- 或
toEnd
#一扔前进(默认)垂直(默认)
D(滚动= 真).fling()
#一扔前进horizentally
D(滚动= 真).fling.horiz.forward()
#一扔向后垂直
D(滚动= 真).fling .vert.backward()
#一扔到horizentally开始
D(滚动= 真).fling.horiz.toBeginning( max_swipes = 1000)
#来结束垂直一扔
D(滚动= 真).fling.toEnd()
- 在特定的ui对象上滚动(可滚动)
可能的属性:
horiz
- 要么
vert
forward
- 或
backward
- 或
toBeginning
- 或
toEnd
- 或
to
#向前滚动(默认)垂直(默认)
D(滚动= 真).scroll(步骤= 10)
#向前滚动horizentally
D(滚动= 真).scroll.horiz.forward(步骤= 100)
#向后滚动垂直
D(滚动= 真).scroll.vert.backward()
#滚动到horizentally开始
D(滚动= 真).scroll.horiz.toBeginning(步骤= 100, max_swipes = 1000)
#滚动到年底垂直
D(滚动= 真)。 scroll.toEnd()
#向前滚动,直到垂直特定的UI对象出现
D(滚动= 真).scroll.to(文= “安全性”)
贡献
- 分叉repo,并克隆到您的计算机。
- 从检出一个新分支
develop
- 的分支
- 安装要求:
pip install -r requirements.txt
- 进行更改,然后更新测试。不要忘记在“提供者”部分的末尾添加您的姓名
- 通过所有的测试和代码必须包括:
tox
- 。
- 提交你的修改,并提交拉请求
develop
- 分支。
贡献者
问题和讨论
如果您有任何错误报告或烦恼请报告给我们的问题跟踪GitHub的问题。
如果你有你想讨论任何建议,新的功能要求或话题,请提交您的主题ostio。
笔记
- Android的uiautomator适用于Android 4.1及以上版本,所以在使用它之前,请确保你的设备是Android4.1 +。
- 有些方法仅工作在Android 4.2 / 4.3,所以你最好阅读详细uiautomator的Java文档在使用它之前。
- 该模块采用uiautomator-jsonrpc服务器作为后台程序与设备进行通信。
- 该模块仅在python2.7 / 3.2 / 3.3 / pypy上测试。
常问问题
- 无法启动JSONRPC服务器:
raise IOError("RPC server not started!")
- 它可能是由网络,设备或环境引起的。因此,当您遇到此问题,请按照以下步骤,尝试手动启动JSONRPC服务器。
- 从下载jar文件uiautomator jsonrpc服务器。
- Adb将下载的jar文件推送到
/data/local/tmp/
- 通过命令启动jsonrpc服务器:
adb shell uiautomator runtest bundle.jar uiautomator-stub.jar -c com.github.uiautomatorstub.Stub
- Adb将本地端口转发到设备端口:
adb forward tcp:9008 tcp:9008
- 检查jsonrpc服务器是否正常:
curl -d '{"jsonrpc":"2.0","method":"deviceInfo","id":1}' localhost:9008/jsonrpc/0
如果你看到类似的消息{"jsonrpc":"2.0","id":1,"result":{"currentPackageName":"android","displayHeight":1280,"displayRotation":0,"displaySizeDpX":0,"displaySizeDpY":0,"displayWidth":720,"productName":"falcon","sdkInt":17,"naturalOrientation":true}}
,则表示服务器已启动。如果你可以手动启动jsonrpc服务器,但你的脚本总是满足IOError("RPC server not started!")
,请提交问题github上的问题。
- 错误
httplib.BadStatusLine: ''
- JsonRPC服务器需要访问设备上的临时目录,但在一些低层设备上,它可能会遇到错误,在访问临时文件没有连接SD卡。因此,如果您遇到错误,请插入SD卡,然后重试。