python中uiautomator_Python-uiautomator使用说明文档

本文档介绍了Python库uiautomator的使用方法,该库是基于Android的uiautomator测试框架,适用于Android 4.1及以上版本。内容包括:设备对象的获取、屏幕操作、按键模拟、手势交互、设备信息获取、监视器和处理程序的注册与使用、选择器的使用等。此外,还提到了如何处理可能出现的问题和错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个Python库是基于Android自带的uiautomator测试框架的一个python封包。适用于Android 4.1以上版本,需要通过adb连接Android设备。

from uiautomator import device as d

d . screen.on()

d(text="Clock").click()

安装

pip install uiautomator

前置条件

安装 Android的SDK,设置Android_home环境以正确的路径。

启动 adb 并且通过usb数据线将电脑与Android设备相连接。

设置Android设备,在开发者选项中允许未知来源应用安装。

导入uiautomator

如果仅有一台设备或在 Android_serial 环境变量中配置。

from uiautomator import device as d

通过设备的设备ID来确定设备对象:

from uiautomator import Device

d=Device('014E05DE0F02000E')

通过其他计算机的端口及连接运行adb服务

虽然 adb 支持sdk 4.3的 -a选项 ,但是现在它有问题。在所有非本地服务上启动adb监听服务使用

adb -a -P 5037 fork-server server &

from uiautomator import Device

d=Device('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( “back”)

#按下键码0×07(‘0’)与ALT (0X02)

d.press(0x07,0X02)

目前下列按键支持上述方法

home

back

left

right

home

back

left

right

up

down

center

menu

search

enter

delete(or del)

recent(recent apps)

volume_up

volume_down

volume_mute

camera

power

down

center

menu

search

enter

delete(or del)

recent(recent apps)

volume_up

volume_down

volume_mute

camera

power

在设备上模拟手势交互

#点击屏幕

# click (x, y) on screen

d.click(x, y)

#长按屏幕

# long click (x, y) on screen

d.long_click(x, y)

滑动

# swipe from (sx, sy) to (ex, ey)

#从sx,sy坐标滑动至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 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)

设备屏幕的事件

有以下几种属性:

natural 或者 n 代替

left 或者 l 代替

right 或者 r 代替

upsidedown或 u(不能设定)

#获取orientation(方向),可能是上述中的任意一种

orientation = d.orientation

#设置定向和冻结旋转。

#说明:"upsidedown"不能用于Android 4.3 以前的版本

d.orientation="l"

d.orientation="r"

d.orientation="n"

锁定/解除旋转

#锁定旋转

d.freeze rotation()

#解除旋转锁定

d.freeze_rotation(False)

屏幕截图

获取屏幕截图并且将其存本机地址中,命名为home.png,不能被用于Android 4.2以前的版本

d.screenshot("home.png")

将屏幕结构储存(就是使用uiautomatorviewer看到的那个结构,以xml格式保存)

#将当前屏幕结构保存在本机并命名为"heierarchy.xml"

d.dump("hierarchy.xml")

#或者将存储值作为结果返回

xml=d.dump()

打开通知消息栏或快速设置

#打开通知消息栏,不能用于Android 4.3以前的版本

d.notification()

#打开快速设置栏,不能用于Android 4.3以前的版本

d.open.quick_settings()

等待空闲或者窗口刷新

# 等待当前窗口空闲

d.wait.idle()

#等待直到窗口发生刷新事件

d.wait.update()

监视器

You can register watcher to perform some actions when a selector can not find a match.

当选择器无法找到匹配时,您可以注册观察器来执行一些操作。

注册监视器

当一个选择器找不到匹配时,uiautomator 会运行全部已经注册的观察者

条件匹配时点击目标

d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \

.click(text="Force Close")

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

(创建一个新的监视器,并将其命名为“name”)

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

(为监视器添加添加一个Uiselector条件)

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

(执行对目标Uiselector点击动作)

条件匹配时按下按键

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.

(为监视器添加一个Uiselector条件)

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

(按顺序依次按下key)

# Alternative way defining key sequence is press(, ..., )

(定义另一种键值序列的方法是‘press(, ..., )’)

检查监视器是否触发

一个监视器触发意味着这个监视器所有条件都匹配并且监视器运行。

d.watcher("watcher_name").triggered

# true in case of the specified watcher triggered, else false

(监视器被触发为‘真’,反之则为‘假’)

删除监视器命名

# remove the watcher

(删除监视器)

d.watcher("watcher_name").remove()

列出所有的监视器

d.watchers

# a list of all registered wachers' names

(一个已注册的监视器名称列表)

检查是否有监视器被触发

d.watchers.triggered

# true in case of any watcher triggered

(在任何监视器被触发的情况下)

重置所有已触发的监视器

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

(重置所有已触发的监视器,并且将d.watchers.triggered 参数变为false)

d.watchers.reset()

删除监视器

# remove all registered watchers

(删除所有已触发的监视器)

d.watchers.remove()

# remove the named watcher, same as d.watcher("watcher_name").remove()

(删除特定名称的监视器,与d.watcher("watcher_name").remove() 相同)

d.watchers.remove("watcher_name")

强制运行所有的监视器

# force to run all registered watchers

(强制运行所有已注册的监视器)

d.watchers.run()

处理程序

处理程序的功能与Watcher相同,只是它实现了我们的Android uiautomator。

处理程序和观察程序之间最不同的用法是,处理程序可以使用自定义的回调函数

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.

(返回True来中断处理程序回调函数的循环)

# turn on the handler callback function(打开处理程序返回函数)

d.handlers.on(fc_close)

# turn off the handler callback function(关闭处理程序返回函数)

d.handlers.off(fc_close)

选择器

选择器是标识当前窗口中的特定UI对象

# To seleted the object ,text is 'Clock' and its className is 'android.widget.TextView'

(对于选择器对象,文字是“Clock”和它的类名是“Android.widget.TextView”)

d(text='Clock', 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对象

子对象

# get the child or grandchild(得到子类或复子类)

d(className="android.widget.ListView").child(text="Bluetooth")

同级对象

# get sibling or child of sibling(得到同级对象或子类)

d(text="Google").sibling(className="android.widget.ImageView")

子类文本或描述或实例

# get the child match className="android.widget.LinearLayout"

(获取子类匹配的 className="android.widget.LinerarLayout")

# and also it or its child or grandchild contains text "Bluetooth"

(而且它或它的子类和复子类包含文本“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_description是找到哪个子类或复子类包含与child_by_text相同的描述说明。

child_by_instance查找一个目标类中子类中特定的UI元素,用于没有滚动可见视图上执行。

详情请参阅以下链接:

UiScrollable, getChildByDescription, getChildByText, getChildByInstance

UiCollection, getChildByDescription, getChildByText, getChildByInstance

上面的方法支持链接调用,例如对于下面的层次结构

...

我们要点击文本“Wi-Fi”右侧的开关打开/打开Wi-Fi。因为有几个开关,几乎相同的属性,所以我们不能使用类似d(className=”android.widget.Switch”)选择的UI对象。相反,我们可以使用下面的代码来选择它。

d(className="android.widget.ListView", resourceId="android:id/list") \

.child_by_text("Wi‑Fi", className="android.widget.LinearLayout") \

.child(className="android.widget.Switch") \

.click()

相对位置

此外,我们可以用相对位置的方法来获取视图: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.

所以对于上面的情况,我们可以写代码:

## select "switch" on the right side of "Wi-Fi"

(选择无线网络连接右侧的开关)

d(text="Wi‑Fi").right(className="android.widget.Switch").click()

多个实例

有时,屏幕可能包含多个视图与相同的例如文本,那么你将不得不使用选择器中的“实例”属性,

如下所示:

d(text="Add new", instance=0)

# which means the first instance with text "Add new"

(这意味着第一个实例是文字“Add new”)

但是,uiautomator提供了类似的方法来使用它。

# get the count of views with text "Add new" on current screen

(统计当前界面中使用文本“Add new”)

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 # ...

注意:当您使用选择器像一个列表时,你必须确保屏幕保持不变,否则你可能会得到UI未找到错误。

获取所选的ui对象状态及其信息

检查特定ui对象是否存在

d(text="Settings").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(text="Settings").clear_text() # clear the text(清除文本信息)

d(text="Settings").set_text("My text...") # set the text(设置文本信息)

对选中的ui对象执行单击操作

点击特定的ui对象

# click on the center of the specific ui object

(点击特定的UI对象的中心)

d(text="Settings").click0()

# click on the bottomright corner of the specific ui object

(点击具体的的UI对象的右下角)

d(text="Settings").click.bottomright()

# click on the topleft corner of the specific ui object

(点击具体的UI对象的左上角)

d(text="Settings").click.topleft()

# click and wait until the new window update

(等待更新后点击)

d(text="Settings").click.wait()

长时间点击特定的ui对象

# long click on the center of the specific ui object

(长按特定的UI对象的中心)

d(text="Settings").long_click()

# long click on the bottomright corner of the specific ui object

(长按特定的UI对象的右下角)

d(text="Settings").long_click.bottomright()

# long click on the topleft corner of the specific ui object

(长按特定UI对象的左上角)

d(text="Settings").long_click.topleft()

针对特定UI对象

# notes : drag can not be set until Android 4.3.

(注:不能用于Android4.3以下的版本)

# drag the ui object to point (x, y)

(拖拽UI对象至点X,Y)

d(text="Settings").drag.to(x, y, steps=100)

# drag the ui object to another ui object(center)

(拖拽某一UI对象到另外一个UI对象(中心))

d(text="Settings").drag.to(text="Clock", steps=50)

从UI对象的中心滑动到UI对象的边缘

滑动支持4个方向:

left

right

top

bottom

d(text="Settings").swipe.right()

d(text="Settings").swipe.left(steps=10)

d(text="Settings").swipe.up(steps=10)

d(text="Settings").swipe.down()

模拟两点同时移动

d(text="Settings").gesture((sx1, sy1), (sx2, sy2)) \

.to((ex1, ey1), (ex2, ey2))

模拟两点在特定的UI对象的上的操作

In,从边到中心

Out,从中心到边缘

# notes : pinch can not be set until Android 4.3.

(注:不能用于Android4.3以下的版本)

# from edge to center. here is "In" not "in"

(从边缘到中心这里使用的是“In”不是“in”)

d(text="Settings").pinch.In(percent=100, steps=10)

# from center to edge

(从中心到边缘)

d(text="Settings").pinch.Out()

同时三点手势模拟

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))

等待特定ui对象出现或消失

# wait until the ui object appears

(等待UI对象出现)

d(text="Settings").wait.exists(timeout=3000)

# wait until the ui object gone

(等待UI对象消失)

d(text="Settings").wait.gone(timeout=1000)

对特定的UI对象执行抛出操作(可滚动)

可能的属性

horiz or vert

(水平或者是垂直的)

forward or backward or toBeginning or toEnd

(向前或向后,去开始位置或者去结束位置)

# 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()

在特定的UI对象上滚动(可滚动)

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 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

(向前滚动,直到特定的UI对象出现)

d(scrollable=True).scroll.to(text="Security")

Contribution

Fork the repo, and clone to your computer.

Checkout a new branch from develop branch

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 develop branch.

贡献者

Xiaocong He (@xiaocong)

Yuanyuan Zou (@yuanyuan)

Qian Jin (@QianJin2013)

Xu Jingjie (@xiscoxu)

Xia Mingyuan (@mingyuan-xia)

问题和讨论

如果您有任何错误报告或问题,烦请提交到 github issues。

备注:

Android的uiautomator适用于Android 4.1及以上版本,所以在使用它之前,请确保你的设备是Android4.1 +。

有些方法仅工作在Android 4.2 / 4.3,所以你最好在使用之前详细阅读uiautomator的Java文档。

该模块采用uiautomator-jsonrpc服务器作为后台程序与设备进行通信。

该模块仅在python2.7 / 3.2 / 3.3 / pypy上测试。

FAQ

1.无法启动JSONRPC服务器: raise IOError(“RPC server not started!”)

它可能是由网络,设备或环境引起的。因此,当您遇到此问题,请按照以下步骤,尝试手动启动JSONRPC服务器。

1)从下载jar文件uiautomator jsonrpc服务器。

2)Adb将下载的jar文件推送到 /data/local/tmp/

3)通过命令启动jsonrpc服务器:

adb shell uiautomator runtest bundle.jar uiautomator-stub.jar -c com.github.uiautomatorstub.Stub

4)adb将本地端口转发到设备端口:

adb forward tcp:9008 tcp:9008

5)检查jsonrpc服务器是否正常

如果你看到类似以下这样的信息:

{“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 issues。

错误 httplib.BadStatusLine: ”

JsonRPC服务器需要访问设备上的临时目录,但在一些底层设备上,它有可能抛出一些错误,在访问临时文件没有连接SD卡。因此,如果您遇到错误,请插入SD卡,然后重试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值