uiautomator 是一个非常强大的 Android UI 自动化测试框架,它最初是由 Sony 开发的,后来被 Google 接管并集成到了 Android 开发者工具中,其核心思想是通过控件的属性(如 text, resource-id, content-desc 等)来定位和操作 UI 元素,而不是依赖于屏幕的绝对坐标,这使得测试脚本更加稳定和可维护。

核心概念:UiDevice 和 UiObject
在使用 uiautomator 时,你会和两个核心概念打交道:
-
UiDevice: 代表你的 Android 设备或模拟器,它是所有操作的入口点,负责设备级别的操作,- 模拟按键(Home, Back, Menu, Volume 等)
- 获取屏幕截图
- 检查屏幕是否锁定
- 获取当前活动包名
-
UiObject: 代表屏幕上的一个 UI 控件(一个按钮、一个文本框、一个列表项等),你可以通过它来:- 获取控件的信息(文本、ID、内容描述等)
- 对控件进行操作(点击、长按、输入文本、滑动等)
- 判断控件是否存在、是否可见、是否被选中
如何安装和配置
1 环境准备
- 安装 Python: 确保你的电脑上安装了 Python (推荐 3.6+)。
- 安装 ADB (Android Debug Bridge): 这是 Android SDK 的一个工具,用于与设备通信。
- Windows: 将
adb.exe所在的目录(通常是Android SDK\platform-tools)添加到系统的PATH环境变量中。 - macOS / Linux: 通常会随 Android Studio 或 Homebrew 安装,同样需要确保其路径在
PATH中。
- Windows: 将
- 开启开发者选项和 USB 调试:
- 在你的 Android 设备上,进入 "设置" -> "关于手机"。
- 连续点击 "版本号" 或 "内部版本号" 7次,直到提示 "你已处于开发者模式"。
- 返回 "设置",找到 "开发者选项",开启 "USB 调试"。
- 连接设备:
- 使用 USB 线连接手机和电脑,或者通过 Wi-Fi 连接(确保在同一局域网内)。
- 在电脑上打开终端或命令提示符,运行
adb devices,如果能看到你的设备序列号,并且后面显示device,则连接成功。
2 安装 Python 库
uiautomator 的 Python 封装库叫做 uiautomator2,它是对原始 uiautomator 的极大改进和扩展,是目前的主流选择。

pip install --pre uiautomator2
3 初始化设备
首次使用时,需要初始化你的设备,安装必要的 ATX (Android Test eXpert) Agent 应用。
import uiautomator2 as u2
# 连接设备(USB连接或Wi-Fi连接)
# USB连接
d = u2.connect_usb()
# Wi-Fi连接(需要先通过USB连接一次获取IP地址)
# d = u2.connect("192.168.1.100:5555")
# 初始化设备,安装或更新ATX Agent
d.session("com.android.settings") # 可以指定任意已安装的App包名来初始化
运行这段代码后,你的手机上会自动安装一个名为 "ATX" 的应用,这是 uiautomator2 的服务端。
核心 API 使用示例
下面是一些最常用的 API 示例,我们假设已经通过 d = u2.connect_usb() 获取了 UiDevice 实例 d。
1 设备级别操作
# 1. 获取设备信息
print("设备名称:", d.info.get('productName'))
print("屏幕分辨率:", d.info.get('displayResolution'))
print("当前包名:", d.current_app()['package'])
# 2. 模拟按键
d.press("home") # 按下 Home 键
d.press("back") # 按下返回键
d.press("recent") # 按下多任务键
# 3. 截图
d.screenshot("screen.png")
# 4. 解锁屏幕(需要配合密码或图案)
if d.info.get('screenOn') == False:
d.unlock() # 需要先设置好锁屏密码
2 控件定位与操作
uiautomator2 提供了非常灵活的定位方式,核心是 d(resourceId="...") 或 d(text="...") 这样的语法。

定位方式:
d(resourceId="com.android.settings:id/title")- 通过资源ID定位(最推荐,最稳定)d(text="WLAN")- 通过文本内容定位d(description="搜索")- 通过内容描述定位d(textContains="设置")- 文本包含d(textStartsWith="Wi")- 文本以...开头d(textMatches="^WLAN$")- 文本匹配正则表达式d(className="android.widget.TextView")- 通过类名定位d(packageName="com.android.settings")- 通过包名定位(通常用于切换应用)d.enabled(True).clickable(True)- 通过属性筛选
操作方法:
.click(): 点击.long_click(): 长按.swipe("left", 0.5): 滑动(百分比方式).drag_to(target_obj): 拖拽到另一个控件.input("Hello World"): 输入文本(适用于输入框)
# 示例:打开手机设置,进入 WLAN 设置
try:
# 1. 启动设置应用
d.app_start("com.android.settings")
print("已启动设置应用")
# 2. 定位 "WLAN" 文本并点击
# 注意:不同手机/系统版本,resource-id 可能不同
wlan_text = d(text="WLAN")
if wlan_text.exists:
wlan_text.click()
print("已点击 WLAN")
else:
# 如果找不到,尝试用 resource-id 定位
d(resourceId="com.android.settings:id/title", text="WLAN").click()
# 3. 等待新页面加载,并查找一个可点击的开关
# 使用 .wait_gone() 等待旧元素消失,表示页面已跳转
wlan_text.wait_gone(timeout=5000) # 等待5秒
# 定位一个开关控件
wifi_switch = d(resourceId="com.android.settings:id/switch_widget")
if wifi_switch.exists:
print(f"WIFI 开关当前状态: {'开启' if wifi_switch.info['checked'] else '关闭'}")
# 点击切换开关
wifi_switch.click()
print("已点击 WIFI 开关")
# 再次检查状态
d(resourceId="com.android.settings:id/switch_widget").wait.exists(timeout=5000)
print(f"WIFI 开关新状态: {'开启' if wifi_switch.info['checked'] else '关闭'}")
# 4. 返回上一页
d.press("back")
except Exception as e:
print(f"发生错误: {e}")
d.press("home") # 发生错误时返回桌面,避免卡在某个页面
finally:
# 5. 关闭设置应用
d.app_stop("com.android.settings")
print("已关闭设置应用")
高级功能
1 选择器
当需要更复杂的定位逻辑时,可以使用 Selector。
from uiautomator2 import Selector
# 组合条件:查找包名是 "com.android.settings" 且文本是 "WLAN" 的控件
selector = Selector().package_name("com.android.settings").text("WLAN")
obj = d(selector)
if obj.exists:
obj.click()
2 Toast 消息处理
Toast 是 Android 中短暂显示的小提示。uiautomator2 可以方便地监听和获取 Toast 消息。
# 启动一个会显示 Toast 的 App(这里用微信举例)
d.app_start("com.tencent.mm")
# 监听 Toast
toast_monitor = d.toast.get_message(5.0, default="") # 等待5秒获取最新的Toast
if toast_monitor:
print(f"获取到 Toast: {toast_monitor}")
# 或者持续监听
print("开始监听 Toast (按 Ctrl+C 停止)...")
try:
while True:
msg = d.toast.get_message(2.0, default=None)
if msg:
print(f"Toast: {msg}")
except KeyboardInterrupt:
print("停止监听 Toast")
3 手势操作
除了对单个控件操作,还可以在屏幕上进行自由的手势。
# 从屏幕 (50%, 50%) 滑动到 (10%, 90%)
d.swipe(0.5, 0.5, 0.1, 0.9)
# 在指定区域内滑动
d.swipe_ext("right", 0.8, scale=0.9) # 在屏幕90%的区域内向右滑动
4 与 Appium 的关系
uiautomator 和 Appium 经常被放在一起比较。
uiautomator: 是一个底层的、专门为 Android 设计的自动化框架。uiautomator2是它的一个现代化 Python 封装。Appium: 是一个跨平台的移动应用自动化测试框架,它内部就是调用了各平台的原生自动化框架(iOS 用 XCUITest,Android 用uiautomator2)。
uiautomator2 是 Appium 在 Android 上的默认“引擎”,你可以直接使用 uiautomator2 进行快速、轻量级的自动化,也可以通过 Appium 来获得更统一的接口、更好的测试报告集成和并行执行能力。
最佳实践和注意事项
- 使用
resourceId定位: 这是uiautomator的最大优势。resourceId在 App 的版本更新中通常最稳定,远比文本或坐标可靠。 - 添加等待和异常处理: UI 操作是异步的,在操作之间添加等待(如
d.wait.exists(timeout=10000))或使用try...except块可以大大提高脚本的稳定性。 - 元素检查: 在操作前,使用
.exists或.wait.exists()检查元素是否存在,避免因元素未找到而报错。 - 清晰的脚本结构: 将常用的操作封装成函数,
login(),search_item(keyword)等,使脚本更易于维护和阅读。 - 清理工作: 在测试脚本的最后,最好能回到桌面或关闭测试应用,确保设备处于一个干净的状态,便于下次测试。
- 性能:
uiautomator2性能不错,但过于频繁的截图或复杂的控件查找仍可能影响速度,应根据需要使用。
希望这份详细的介绍能帮助你快速上手 uiautomator 库!
