Android UI 自动化的异步 Python 客户端
Project description
async-uiautomator2
async-uiautomator2 是面向 Android UI 自动化的异步 Python 客户端。它不修改
u2.jar,也不重写 Android 端服务,而是在 Python 侧把 uiautomator2 的关键能力整理成
async API。
第一版重点是:
- 使用 ADB socket 直连设备端
u2.jar:9008,不依赖本地adb forward。 - 使用
asyncio.to_thread包装同步adbutils,避免直接阻塞事件循环。 - 提供 typed selector:
d.select(text="确定"),不实现d(text="确定")。 - 提供基于 XML dump 的异步 XPath,用于弹窗检测和临时定位。
- 用锁保护
u2.jar启动、停止和自动重启。
u2.jar 获取方式
默认不依赖仓库里的 experiment/ 目录,也不要求用户手动复制 jar。启动时会按顺序解析:
async_connect(..., jar_path="...")显式传入的路径。- 已安装包中的
assets/u2.jar资源,例如uiautomator2自带的资源。 - 本机缓存目录中的
u2-<version>.jar。 - 从
uiautomator2/assets/sync.sh使用的 jar 源自动下载到缓存:https://public.uiauto.devsleep.com/u2jar/0.2.2/u2.jar。
可用环境变量覆盖缓存目录:
$env:ASYNC_UIAUTOMATOR2_CACHE_DIR="D:\cache\async-uiautomator2"
安装
uv add async-uiautomator2
本仓库开发环境:
uv sync
uv run pytest -q
基础用法
import asyncio
from async_uiautomator2 import async_connect
async def main():
async with await async_connect("emulator-5554") as d:
print(await d.info)
await d.click(100, 200)
print(await d.dump_hierarchy())
asyncio.run(main())
如果不使用 async with,脚本结束前需要显式关闭:
d = await async_connect("emulator-5554")
try:
await d.click(100, 200)
finally:
await d.close()
Typed Selector
推荐使用显式字段:
ok = d.select(
text="确定",
resource_id="com.example:id/ok",
clickable=True,
)
if await ok.exists:
await ok.click()
常用字段会从 Python 风格转换为 uiautomator2 原始字段:
| Python 字段 | 原始字段 |
|---|---|
text_contains |
textContains |
text_starts_with |
textStartsWith |
class_name |
className |
resource_id |
resourceId |
package_name |
packageName |
long_clickable |
longClickable |
需要临时使用原始字段时,可以走逃生口:
await d.select_raw(textContains="确定").click()
XPath
XPath 会先异步调用 dumpWindowHierarchy 获取 XML,再在 Python 侧匹配:
if await d.xpath("权限请求").exists:
await d.xpath("允许").click()
支持 uiautomator2.xpath 的常用简写:
| 写法 | 含义 |
|---|---|
"确定" |
匹配 text、content-desc 或 resource-id 等于该值 |
"@com.example:id/ok" |
匹配 resource-id |
"%确定%" |
text 或 content-desc 包含该值 |
"确定%" |
text 或 content-desc 前缀匹配 |
"%确定" |
text 或 content-desc 后缀匹配 |
"//android.widget.Button" |
标准 XPath |
FastAPI 常驻服务
from async_uiautomator2 import async_connect
devices = {}
async def startup():
devices["emulator-5554"] = await async_connect("emulator-5554")
async def click_ok(serial: str):
d = devices[serial]
if await d.xpath("允许").exists:
await d.xpath("允许").click()
并发规则
- 多台设备可以用
asyncio.gather()自然并发。 - 同一设备上的启动、停止、重启由 server 层锁保护。
- UI 操作仍应按业务流程顺序执行,不建议在同一台设备上并发乱点。
- 长时间 shell/push 通过线程隔离阻塞,但第一阶段不保证取消后设备端命令立即回滚。
第一阶段限制
- 不完整复制
uiautomator2的所有 API。 - 不修改或重写
u2.jar。 - 不实现纯异步 ADB 协议。
- 不实现
d(text="OK")或d(**kwargs)。
开发验证
uv run pytest -q
uv run python -m compileall -q src/async_uiautomator2
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file async_uiautomator2-0.1.0.tar.gz.
File metadata
- Download URL: async_uiautomator2-0.1.0.tar.gz
- Upload date:
- Size: 13.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.10 {"installer":{"name":"uv","version":"0.9.10"},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18fae575439460bd132d76eac8271f57e218ed1f2aded48f04a5c8d908796f74
|
|
| MD5 |
08249d7a2bbbf413bab12264ca925bde
|
|
| BLAKE2b-256 |
120236b8c44dad734ead99caf32b189a544fc954fe3c5b818c0b67eae5a2acd5
|
File details
Details for the file async_uiautomator2-0.1.0-py3-none-any.whl.
File metadata
- Download URL: async_uiautomator2-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.10 {"installer":{"name":"uv","version":"0.9.10"},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e40beefed2bebdb745a93997557d22dfe7e67571b2f5199067ce6c16930b461
|
|
| MD5 |
856f3bed85c6b967d81e1f3bb4a9dcf4
|
|
| BLAKE2b-256 |
544dc796c4561c762257b1b94387a68101c9ca94eb16ba71101aa82de717687a
|