Android Uiautomator2 Python Wrapper完全指南:从安装到自动化测试全流程

Android Uiautomator2 Python Wrapper完全指南:从安装到自动化测试全流程

【免费下载链接】uiautomator2 Android Uiautomator2 Python Wrapper 【免费下载链接】uiautomator2 项目地址: https://gitcode.com/gh_mirrors/ui/uiautomator2

1. 引言:告别繁琐的Android自动化测试

你是否还在为Android应用的自动化测试而烦恼?面对复杂的UI交互、不稳定的元素定位和冗长的测试脚本,你是否渴望一种更高效、更简洁的解决方案?Android Uiautomator2 Python Wrapper(以下简称uiautomator2)正是为解决这些痛点而生。作为一个强大的Python库,它封装了Android Uiautomator2的核心功能,让你能够用简洁的Python代码实现复杂的Android自动化测试。

读完本文,你将获得:

  • 从环境搭建到脚本编写的全流程掌握
  • 高效定位和操作UI元素的技巧
  • 处理复杂手势和场景的实战经验
  • 构建稳定可靠的自动化测试框架的方法

2. 核心概念与工作原理

2.1 Uiautomator2是什么?

Uiautomator2是Google提供的一个Android UI自动化测试框架,基于Accessibility服务,允许开发者与设备上的任何应用进行交互。而uiautomator2 Python Wrapper则是对这一框架的Python封装,通过HTTP RPC服务将设备端的功能暴露给Python客户端,实现了用Python控制Android设备的能力。

mermaid

2.2 核心优势

uiautomator2相比其他自动化测试工具具有以下显著优势:

特性uiautomator2AppiumEspresso
运行速度⚡⚡⚡ (毫秒级响应)⚡ (秒级响应)⚡⚡ (较快)
环境依赖少 (仅需ADB)多 (Java, Node.js等)多 (Android SDK)
易用性高 (Python API简洁)中 (需学习复杂配置)低 (Java/Kotlin开发)
跨平台支持仅AndroidAndroid/iOS仅Android
社区活跃度

3. 环境搭建与安装

3.1 系统要求

  • Android设备:Android 4.4+ (API level 19+)
  • Python环境:Python 3.8+
  • 开发计算机:Windows/macOS/Linux

3.2 安装步骤

3.2.1 安装Python库
pip install -U uiautomator2

验证安装是否成功:

uiautomator2 --help
3.2.2 安装UI检查工具

uiautomator2推荐使用uiauto.dev作为UI元素检查工具:

pip install uiautodev
uiauto.dev

打开浏览器访问 https://uiauto.dev 即可查看设备当前界面结构。

3.3 设备连接配置

确保Android设备已开启"开发者选项"和"USB调试",并通过USB连接到计算机。验证设备连接:

adb devices

应输出类似以下内容:

List of devices attached
123456f device

4. 快速入门:第一个自动化脚本

4.1 连接设备

import uiautomator2 as u2

# 连接设备
d = u2.connect('123456f')  # '123456f'是设备序列号,可通过adb devices获取
# 或如果只有一个设备连接,可简化为
d = u2.connect()

# 验证连接
print(d.info)

成功连接后,将输出设备基本信息,如:

{
    'currentPackageName': 'com.android.launcher',
    'displayHeight': 1920,
    'displayRotation': 0,
    'displaySizeDpX': 411,
    'displaySizeDpY': 731,
    'displayWidth': 1080,
    'productName': 'OnePlus5',
    'screenOn': True,
    'sdkInt': 27,
    'naturalOrientation': True
}

4.2 基本操作示例

以下是一个简单的自动化脚本,演示了启动应用、点击按钮和输入文本的基本操作:

import uiautomator2 as u2

# 连接设备
d = u2.connect()

# 设置隐式等待时间(默认20秒)
d.implicitly_wait(10.0)

# 启动计算器应用
d.app_start("com.android.calculator2")

# 确保应用已启动
d.wait_activity(".Calculator", timeout=10)

# 执行2 + 3 = 5的计算
d(text="2").click()
d(text="+"").click()
d(text="3").click()
d(text="=").click()

# 验证结果
result = d(resourceId="com.android.calculator2:id/result").get_text()
print(f"计算结果: {result}")  # 应输出"5"

# 关闭应用
d.app_stop("com.android.calculator2")

5. 设备连接与管理

5.1 连接方式

uiautomator2支持多种设备连接方式:

5.1.1 USB连接
# 通过设备序列号连接
d = u2.connect('123456f')  # 设备序列号可通过adb devices获取

# 如果只有一个设备连接,可简化
d = u2.connect()
5.1.2 网络连接

首先确保设备与计算机在同一网络,然后通过IP连接:

d = u2.connect('192.168.1.100:5555')

5.2 设备信息获取

# 获取基本设备信息
print(d.info)

# 获取详细设备信息
print(d.device_info)

# 获取屏幕尺寸
width, height = d.window_size()
print(f"屏幕尺寸: {width}x{height}")

# 获取WLAN IP
print(f"WLAN IP: {d.wlan_ip}")

# 获取设备序列号
print(f"设备序列号: {d.serial}")

示例输出:

{
    'serial': '123456f',
    'sdk': 27,
    'brand': 'OnePlus',
    'model': 'OnePlus5',
    'arch': 'arm64-v8a',
    'version': 8.1
}
屏幕尺寸: 1080x1920
WLAN IP: 192.168.1.100
设备序列号: 123456f

6. UI元素定位与操作

6.1 Selector选择器

uiautomator2提供了强大的Selector机制来定位UI元素,支持多种属性匹配:

# 通过文本定位
d(text="设置").click()

# 通过资源ID定位
d(resourceId="com.android.settings:id/search").click()

# 通过类名定位
d(className="android.widget.Button").click()

# 组合条件定位
d(text="设置", className="android.widget.TextView").click()

支持的选择器属性包括:

属性描述示例
text元素文本text="设置"
textContains文本包含textContains="设"
textMatches文本正则匹配textMatches="^设.*"
resourceId资源IDresourceId="com.android.settings:id/title"
className类名className="android.widget.TextView"
description元素描述description="搜索"
checkable是否可勾选checkable=True
checked是否已勾选checked=True
clickable是否可点击clickable=True
enabled是否启用enabled=True

6.2 XPath定位

除了Selector,uiautomator2还支持XPath定位,特别适合复杂UI结构:

# 基本XPath定位
d.xpath("//android.widget.TextView[@text='设置']").click()

# 相对路径定位
d.xpath("//*[@resource-id='com.android.settings:id/list']/android.widget.LinearLayout[2]").click()

# 文本包含定位
d.xpath("//*[contains(@text, '无线')]").click()

# 获取所有匹配元素
elements = d.xpath("//android.widget.Button").all()
for element in elements:
    print(element.get_text())

6.3 常用元素操作

# 点击操作
d(text="设置").click()

# 长按操作
d(text="设置").long_click()

# 获取文本
text = d(text="设置").get_text()

# 设置文本
d(resourceId="com.android.settings:id/search").set_text("WiFi")

# 清空文本
d(resourceId="com.android.settings:id/search").clear_text()

# 判断元素是否存在
exists = d(text="设置").exists
print(f"元素是否存在: {exists}")

# 等待元素出现
d(text="设置").wait(timeout=10)  # 等待10秒

# 滑动查找元素
d(text="关于手机", scrollable=True).click()

7. 手势操作与交互

7.1 基本手势

# 点击屏幕坐标
d.click(500, 1000)  # (x, y)

# 双击
d.double_click(500, 1000)

# 长按
d.long_click(500, 1000, duration=2)  # 长按2秒

# 滑动
d.swipe(100, 500, 900, 500, duration=0.5)  # 从左到右滑动,持续0.5秒

# 拖动
d.drag(100, 500, 900, 500, duration=1)  # 拖动操作,持续1秒

7.2 扩展滑动操作

from uiautomator2 import Direction

# 向指定方向滑动
d.swipe_ext(Direction.RIGHT)  # 向右滑动
d.swipe_ext(Direction.UP)     # 向上滑动

# 控制滑动距离比例
d.swipe_ext(Direction.DOWN, scale=0.8)  # 向下滑动,距离为屏幕高度的80%

# 在指定区域内滑动
d.swipe_ext(Direction.LEFT, box=(0, 0, 500, 500))  # 在左上角区域向左滑动

7.3 多点触控与手势

# 两点缩放(如图片放大)
d pinch_in()  # 缩小
d pinch_out() # 放大

# 自定义手势路径
d.swipe_points([(100, 1000), (300, 800), (500, 1000), (700, 800), (900, 1000)], 0.5)

8. 应用管理

8.1 应用安装与卸载

# 安装应用(支持本地APK或URL)
d.app_install("https://example.com/app.apk")

# 卸载应用
d.app_uninstall("com.example.app")

# 强制停止应用
d.app_stop("com.example.app")

# 清除应用数据
d.app_clear("com.example.app")

8.2 应用启动与切换

# 启动应用
d.app_start("com.example.app")

# 启动应用并等待
d.app_start("com.example.app", wait=True)

# 启动指定Activity
d.app_start("com.example.app", ".MainActivity")

# 获取当前前台应用
current_app = d.app_current()
print(f"当前应用: {current_app['package']}")

# 等待应用启动
pid = d.app_wait("com.example.app")  # 返回应用PID
if pid == 0:
    print("应用启动失败")
else:
    print(f"应用启动成功,PID: {pid}")

8.3 应用信息获取

# 获取应用信息
app_info = d.app_info("com.example.app")
print(f"应用版本: {app_info['versionName']}")
print(f"版本号: {app_info['versionCode']}")

# 获取所有已安装应用
all_apps = d.app_list()
print(f"已安装应用数量: {len(all_apps)}")

# 获取所有运行中应用
running_apps = d.app_list_running()
print(f"运行中应用: {running_apps}")

9. 高级功能

9.1 监控与处理弹窗(Watcher)

自动化测试中,弹窗(如广告、权限请求)常常干扰测试流程。uiautomator2的Watcher功能可以自动监控并处理这些弹窗:

# 创建Watcher
d.watcher("ALERT").when(text="允许").click()
d.watcher("ALERT").when(text="取消").click()

# 启动所有Watcher
d.watcher.start()

# 启动Watcher并设置触发次数限制
d.watcher.start(2)  # 最多触发2次

# 检查是否有Watcher被触发
if d.watcher("ALERT").triggered:
    print("ALERT Watcher已触发")

# 重置Watcher
d.watcher.reset()

# 停止所有Watcher
d.watcher.stop()

9.2 截图与屏幕录制

# 截取屏幕并保存
d.screenshot("screenshot.jpg")

# 获取PIL Image对象
image = d.screenshot()
image.save("screenshot.png")

# 屏幕录制
d.screenrecord("recording.mp4")
# 录制10秒后停止
import time
time.sleep(10)
d.screenrecord.stop()

9.3 处理Toast消息

# 获取最新Toast消息
toast = d.last_toast
print(f"最新Toast: {toast}")

# 等待特定Toast出现
if d.wait_for_toast("操作成功", timeout=5):
    print("Toast出现")
else:
    print("Toast未出现")

9.4 键盘与输入

# 发送文本(需先聚焦输入框)
d.send_keys("hello world")

# 发送按键事件
d.press("back")        # 返回键
d.press("home")        # Home键
d.press("volume_up")   # 音量加
d.press("power")       # 电源键

# 长按按键
d.long_press("power")  # 长按电源键

# 设置剪贴板内容
d.set_clipboard("hello clipboard")

# 获取剪贴板内容
clipboard = d.clipboard
print(f"剪贴板内容: {clipboard}")

10. 测试框架集成与实战

10.1 与pytest集成

uiautomator2可以无缝集成pytest,构建强大的自动化测试框架:

# test_app.py
import uiautomator2 as u2
import pytest

@pytest.fixture(scope="module")
def d():
    # 连接设备
    d = u2.connect()
    # 设置隐式等待时间
    d.implicitly_wait(10.0)
    # 启动应用
    d.app_start("com.example.app")
    yield d
    # 测试结束后停止应用
    d.app_stop("com.example.app")

def test_login(d):
    # 输入用户名密码
    d(resourceId="com.example.app:id/et_username").set_text("testuser")
    d(resourceId="com.example.app:id/et_password").set_text("password123")
    # 点击登录按钮
    d(resourceId="com.example.app:id/btn_login").click()
    # 验证登录成功
    assert d(text="欢迎回来,testuser").exists

def test_logout(d):
    # 点击个人中心
    d(resourceId="com.example.app:id/nav_profile").click()
    # 点击退出登录
    d(text="退出登录").click()
    # 确认退出
    d(text="确定").click()
    # 验证登录页面
    assert d(resourceId="com.example.app:id/btn_login").exists

运行测试:

pytest test_app.py -v

10.2 处理复杂场景

10.2.1 滑动列表查找元素
def find_and_click(d, text):
    """滑动查找文本并点击"""
    max_swipes = 5
    swipe_count = 0
    
    while swipe_count < max_swipes:
        if d(text=text).exists:
            d(text=text).click()
            return True
        # 向上滑动
        d.swipe_ext(Direction.UP)
        swipe_count += 1
    
    return False

# 使用示例
find_and_click(d, "关于手机")
10.2.2 处理动态加载内容
def wait_for_element(d, **kwargs):
    """等待元素出现"""
    timeout = d.settings['wait_timeout']
    start_time = time.time()
    
    while time.time() - start_time < timeout:
        if d(** kwargs).exists:
            return True
        time.sleep(0.5)
    
    return False

# 使用示例
if wait_for_element(d, text="加载完成"):
    print("内容加载完成")
else:
    print("内容加载超时")

10.3 测试报告生成

结合pytest-html插件生成美观的测试报告:

pip install pytest-html
pytest test_app.py -v --html=report.html --self-contained-html

11. 性能优化与最佳实践

11.1 提高元素定位稳定性

# 设置隐式等待时间
d.implicitly_wait(10.0)  # 全局设置,单位秒

# 显式等待元素
d(text="设置").wait(timeout=5)  # 等待5秒

# 使用资源ID定位(比文本定位更稳定)
d(resourceId="com.android.settings:id/title", text="设置").click()

11.2 减少不必要的等待

# 不好的实践
time.sleep(5)  # 固定等待5秒,可能导致测试缓慢

# 好的实践
d.wait_activity(".MainActivity", timeout=10)  # 等待特定Activity
if d(text="加载中").exists:
    d(text="加载完成").wait()  # 仅在需要时等待

11.3 异常处理

try:
    d(text="设置").click()
except UiObjectNotFoundError:
    print("未找到设置按钮,尝试滑动查找")
    d.swipe_ext(Direction.UP)
    d(text="设置").click()
except Exception as e:
    print(f"发生异常: {str(e)}")
    d.screenshot("error.png")  # 捕获异常时截图

11.4 代码组织最佳实践

project/
├── common/                # 公共工具函数
│   ├── __init__.py
│   ├── element_finder.py  # 元素查找工具
│   └── gesture_utils.py   # 手势操作工具
├── pages/                 # Page Object模型
│   ├── __init__.py
│   ├── login_page.py      # 登录页面
│   └── home_page.py       # 首页
├── tests/                 # 测试用例
│   ├── __init__.py
│   ├── test_login.py
│   └── test_home.py
└── conftest.py            # pytest配置

12. 常见问题与解决方案

12.1 元素定位失败

问题:明明存在的元素却定位不到。

解决方案

  1. 检查元素属性是否动态变化(如resourceId包含随机数)
  2. 确保元素在当前界面可见,可能需要滑动
  3. 尝试不同的定位方式(如从文本定位改为资源ID定位)
  4. 增加等待时间或使用显式等待
# 解决动态元素问题
d.xpath("//*[contains(@resourceId, 'dynamic_id_')]").click()

# 确保元素可见
if not d(text="按钮").exists:
    d.swipe_ext(Direction.UP)
d(text="按钮").click()

12.2 测试脚本不稳定

问题:相同的脚本有时成功有时失败,不稳定。

解决方案

  1. 避免使用坐标操作,尽量使用UI属性
  2. 增加关键步骤的验证
  3. 使用Watcher处理意外弹窗
  4. 减少测试用例间的依赖
# 增加验证步骤
d(text="登录").click()
assert d(text="欢迎").exists, "登录失败"

12.3 处理权限请求

问题:Android 6.0+需要动态权限申请,干扰自动化流程。

解决方案

  1. 测试前手动授予所有必要权限
  2. 使用ADB命令授予权限
  3. 结合Watcher自动处理权限弹窗
# 使用ADB授予权限
d.shell("pm grant com.example.app android.permission.CAMERA")
d.shell("pm grant com.example.app android.permission.WRITE_EXTERNAL_STORAGE")

# 使用Watcher自动处理
d.watcher("PERMISSION").when(text="允许").click()
d.watcher.start()

13. 总结与展望

13.1 核心优势回顾

uiautomator2作为Android自动化测试工具,凭借其毫秒级响应速度、简洁的Python API和强大的UI交互能力,为开发者提供了高效便捷的自动化测试解决方案。无论是快速原型验证、回归测试还是持续集成,uiautomator2都能显著提高测试效率,降低维护成本。

13.2 进阶学习资源

13.3 未来展望

随着Android系统的不断更新,uiautomator2也在持续进化。未来可能的发展方向包括:

  • 更好地支持Android 12+的新特性
  • 增强AI驱动的元素识别能力
  • 与更多CI/CD工具集成
  • 提供更丰富的测试报告和分析功能

掌握uiautomator2,让Android自动化测试变得简单而高效。现在就动手尝试,体验自动化测试的魅力吧!

14. 常见问题FAQ

Q1: uiautomator2支持iOS设备吗?
A1: 不支持。iOS自动化测试可考虑facebook-wda

Q2: 如何处理WebView中的元素?
A2: uiautomator2对WebView支持有限,复杂场景建议结合Selenium或Appium。

Q3: 测试过程中如何记录日志?
A3: 可使用Python内置logging模块,或uiautomator2的调试模式:

d.debug = True  # 启用调试模式,打印HTTP请求信息

Q4: 如何实现多设备并行测试?
A4: 可结合pytest-xdist实现分布式测试,或使用atxserver2进行设备管理。

Q5: uiautomator2与Appium如何选择?
A5: 简单场景、追求速度选uiautomator2;跨平台需求、复杂WebView场景选Appium。

【免费下载链接】uiautomator2 Android Uiautomator2 Python Wrapper 【免费下载链接】uiautomator2 项目地址: https://gitcode.com/gh_mirrors/ui/uiautomator2

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值