uitap
uiautomator2 式 iOS 设备自动化客户端。 pip install uitap,零运行时依赖(模板匹配的 Pillow 可选),通过设备端已有的 9096 HTTP 服务与 10102 日志 WebSocket 提供截图、控件树、坐标操作、工程管理、OCR、日志与自动化能力。
完整中文文档:从零开始使用教程、API 使用参考、生产使用指南、USB 隧道运维指南、发布与验收流程、变更说明。
前置条件
- 手机上已安装并开启设备服务(AScript 应用中的开发者服务),电脑与手机同一网络;USB 场景见下文。
- Python 3.10+。命令行默认缩写为
ut(uitap为全名,二者等价;py -m uitap不依赖 PATH)。
最短上手
pip install uitap
ut init
edit uitap.json
ut status
init 在当前目录生成一份包含全部配置键的 uitap.json,并自动填入已安装的 iproxy 路径;它不连接设备,可在手机就绪前先执行。已存在同名文件时拒绝覆盖,确需重建加 --force。把 device.address 改为手机页面显示的地址(例如 192.168.1.100:9096;USB 场景保持默认 127.0.0.1:9096),然后 ut status 输出的 "available": true 即连接成功。接着用五行 Python 完成第一次自动化:
from uitap import connect
device = connect("192.168.1.100:9096") # 与 uitap.json 中一致
print(device(text="登录").count) # 先确认恰好命中一个控件
device(text="登录").click() # 确认无误后再点击
任务速查
device 指 connect() 返回的对象,client 指低层 Client(可从 device.client 取得);timeout、interval 单位为秒,只有带 _ms 后缀的参数才使用毫秒。完整参数见 API 使用参考。
| 我想… | 写法 |
|---|---|
| 截图留证 | device.screenshot("evidence/step.png") |
| 点击文本为“登录”的按钮 | device(text="登录").click() |
| 按控件名(accessibility name)定位 | device(name="login_button") |
| 确认控件存在 / 数量 | device(text="登录").exists / .count |
| 等控件出现(最多 10 秒) | device(text="首页").get(timeout=10) |
| 等控件出现,超时直接报错 | device.wait(device.selector().text("首页"), timeout=10) |
| 等控件消失 | device(text="弹窗").wait_gone(timeout=10) |
| 找到才点击,找不到不报错 | device(text="同意").click_exists(timeout=5) |
| 输入文本(自动先点击控件取得焦点) | device(resource_id="username").set_text("hello") |
| 等图片出现并返回坐标 | client.wait_image("assets/login.png", confidence=0.95) |
| 等图片出现后点击中心 | client.tap_image("assets/继续.png", timeout=10) |
| 等 loading 图片消失再继续 | client.wait_image_gone("assets/loading.png", timeout=20) |
| 滚动列表直到目标图片出现 | client.scroll_until_image("assets/target.png", direction="up") |
| 滚动列表直到目标控件出现 | device.scroll_until_element(device.selector().name("提交"), direction="up") |
| 弹窗出现自动点击(后台监控) | with device.watch(device.selector().text("允许"), interval=1.5): ... |
| 按屏幕比例点击(底部中央) | device.click_rel(0.5, 0.92) |
| 按屏幕比例滑动 | client.swipe_relative(0.5, 0.8, 0.5, 0.2) |
| 识别屏幕文字 | client.ocr() |
| 找含“登录”二字的 OCR 文本(含坐标) | client.find_ocr_text("登录") |
| 等屏幕出现指定文字 | client.wait_ocr_text("登录成功", timeout=10) |
| 读取一个像素的 RGB/HEX | client.pixel(100, 200).rgb / .hex |
| 按比例读取像素颜色 | client.pixel_relative(0.5, 0.92) |
| 断言某点是某颜色(带容差) | client.assert_color(100, 200, "#FFFFFF", tolerance=3) |
| 区域内找/数某种颜色 | client.find_color("#FF0000", region=(0, 1800, 1179, 2556)) / client.count_color(...) |
| 长按 / 双击(绝对坐标) | client.long_press(600, 1200, duration=0.8) / client.double_tap(600, 1200) |
| 按比例长按 / 双击 | client.long_press_relative(0.5, 0.5, duration=0.8) |
| 拖拽(绝对 / 比例) | client.drag(200, 1000, 900, 1000, duration=0.5) / client.drag_relative(0.2, 0.5, 0.8, 0.5) |
| 元素长按 / 双击 / 拖到某点 | element.long_click() / element.double_click() / element.drag_to(800, 1200) |
| 等目标 App 成为前台 | client.wait_current_app("com.example.app", timeout=10) |
| 启动 / 停止 App | client.app_start("com.example.app") / client.app_stop("com.example.app") |
| 查 App 运行状态 | client.app_state("com.example.app")["state"] |
| 锁屏 / 解锁 | client.lock_screen() / client.unlock_screen() |
| 读写设备剪贴板 | client.set_clipboard("code") / client.get_clipboard() |
| 查当前屏幕方向 | client.orientation() |
| 打开 URL / 深链 | client.open_url("myapp://page") |
| 发送按键(home/音量/电源) | client.press_key("home") |
| 读取元素文本 | device(label="标题").get_text() |
| 清空元素文本 | 暂不可用(设备端限制,见 API 参考 get_text 行) |
| 多段轨迹滑动 | client.slide_path([(1800, 1300), (600, 1300)], durations=[150, 150]) |
| 长按拖拽(三段停留) | client.touch_and_slide(600, 1300, 1800, 1300) |
| 矩形内随机点击 | client.click_random(300, 500, 900, 1000) |
| 拟人抖动点击 | client.tap(600, 1300, jitter=5) |
| SIFT 特征匹配 | client.find_sift(["~/res/img/x.png"], threshold=0.7) |
| 二维码/条码识别 | client.scan_code() |
| YOLO 目标检测 | client.yolov_load(p, b, yaml) → client.yolov_detect(threshold=0.5) |
| 设备端整帧缓存 | client.screen_cache(True)(批量找色/OCR 前开) |
| 系统通知 | client.notify("跑完了", title="uitap") |
| 元素内滚动 / 滚动查找 | element.scroll("down", 0.8) / element.scroll_to(device.selector().name("目标")) |
| 查电池 / 设备信息 | client.battery_info() / client.device_info() |
| 查到唯一元素才点击(锁内原子) | device.click_if_unique(device.selector().name("提交")) |
| 一帧中找多个模板 | client.find_images({"成功": "success.png", "失败": "failure.png"}) |
| 等待任意页面结果 | name, match = client.wait_any_image({...}, timeout=20) |
| 本地快照关系查询 | device.snapshot()(name="表单").child(device.selector().text("提交")) |
| 读取控件树 XML 字符串 | device.dump_hierarchy() |
| 每步自动留证据的可靠执行 | run.step("登录", login.click, capture_after=True) |
| 等待日志出现标记 | client.wait_for_log("READY", timeout=10) |
| 在 Python 中管理 USB 隧道(读配置) | with Tunnel.from_config() as tunnel: |
IDE 提示
包内置类型注解、中文 docstring 和 py.typed 标记。安装后在 PyCharm 或 VS Code/Pylance 中输入 client.、device. 或将鼠标悬停在方法上,可看到参数类型、中文单位说明、默认值与返回类型。参数名保持英文以兼容 Python 生态。
from uitap import Client
device = Client("192.168.1.100:9096")
device.save_screenshot("screen.png")
# tap/swipe 使用截图的物理像素坐标;先用 action_size() 确认尺寸。
device.tap(600, 1800)
device.upload_file("demo", "__init__.py")
device.run_project("demo")
安装与配置
pip install uitap
ut init
edit uitap.json
ut doctor
从 PyPI 安装(推荐):pip install uitap;升级用 pip install --upgrade uitap。Windows 上 pip 未加入 PATH 时改用 py -m pip install uitap(macOS/Linux 用 python3 -m pip)。
源码仓库安装(开发场景):py -m pip install --user --upgrade .,Windows 上推荐 py -m uitap(不依赖 Scripts 目录是否加入 PATH)。真实 uitap.json 已被 Git 忽略,其中的密码、UDID 与内网地址不得提交;init 在检测到配置未被忽略时会主动警告。
需要模板匹配、找图等视觉功能时,改用 pip install "uitap[vision]" 一并安装 Pillow 与 OpenCV(opencv-python-headless);OpenCV 用于模糊匹配加速,未安装时自动降级到纯 Pillow 实现,功能不受影响。
常用配置项:
language:auto、zh-CN或en。auto时中文系统输出中文,其他系统输出英文。device.address:Wi-Fi 场景填写手机服务地址,例如192.168.1.100:9096;USB 场景填写127.0.0.1:9096。device.password:设备服务密码;留空表示不发送密码 Cookie。tunnel:USBiproxy的可执行文件、UDID 和端口配置。
单次命令可使用 --device、--password、--timeout 与 --lang 覆盖配置文件。这些都是全局参数,必须写在子命令之前(例如 ut --device 127.0.0.1:9096 status);只有 --yes 允许写在子命令之后。优先级统一为“命令行参数 > 配置文件 > 内置默认值”。
快速诊断与 USB 连接
ut help 查看中文命令速查。ut doctor 会只读检查 iproxy、隧道端口、控制服务、日志服务和 status 兼容性;默认不修改电脑或手机。
电脑与手机不在同一网络时,安装受信任来源的 iproxy 后执行:
ut doctor
ut tunnel
tunnel 会同时映射 127.0.0.1:9096 -> 手机:9096 与 127.0.0.1:10102 -> 手机:10102。保持该终端运行,再打开第二个终端执行:
ut status
ut log 10
ut inspect
USB 场景下 device.address 必须是 127.0.0.1:9096。端口冲突时可用 tunnel --local-port / --local-log-port 改用其他本地端口,但 tunnel 不会自动改写配置,业务命令需同步用 --device 127.0.0.1:<新端口> 指向新端口;多设备并行时再用 --udid 固定目标手机。完整参数表见 USB 隧道运维指南。若已安装 iproxy.exe 但未加入 PATH,可执行 ut doctor --fix-iproxy "D:\\tools\\libimobiledevice\\iproxy.exe";工具会显示修改计划,并在确认后才写入本地配置。
自动化对象 API
from uitap import connect
device = connect("192.168.1.100:9096")
confirm = device(text="Confirm", class_name="XCUIElementTypeButton")
if confirm.exists:
print(confirm.info)
confirm.click()
# 也支持稳定的显式选择器和坐标点探测。
device.selector().name("login_button")
device.selector().at(200, 600) # 绝对物理像素
device.selector().at_relative(0.5, 0.5) # 屏幕比例坐标
坐标规则统一如下:无后缀方法一律使用截图物理像素绝对坐标,例如 tap(x, y)、swipe(...)、Selector.at(x, y)、pixel(x, y)、screenshot_crop(left, top, right, bottom);*_relative 一律使用 0..1 比例坐标。所有矩形均为 left, top, right, bottom,左上包含、右下排除。控件树、截图、OCR 与 tap/swipe 使用物理像素,坐标始终跟随当前屏幕方向(竖屏如 1179 x 2556,横屏自动变为 2556 x 1179,已在真机横屏验证);只有 status()["logical_screen"] 保留移动端原始逻辑点,供协议诊断使用。
# 保存屏幕下半部分(比例裁剪)。
device.save_screenshot_crop_relative("artifacts/bottom.png", 0, 0.5, 1, 1)
本机模板可等待图标出现/消失,也可指定置信度。容差匹配(confidence < 1.0)会优先读取设备已存在的 HID JPEG 帧;HID 不可用时自动回退 PNG,无需为 USB 场景引入另一套 API。精确匹配(confidence=1.0)、截图留证与取色仍使用无损 PNG。
match = device.wait_image("assets/login-icon.png", confidence=0.95, timeout=15, log=True)
device.tap(*match.center)
device.wait_image_gone("assets/loading.png", confidence=0.90, timeout=20, log=True)
# 自定义比例手势与每次滑动时长。
match = device.scroll_until_image("assets/target.png", swipe_relative=(0.7, 0.75, 0.35, 0.25), duration=0.65)
生产工作流建议使用 Run。它会将同一设备的动作串行化,并为每一步写入独立证据目录:
from uitap import Run, connect
device = connect("192.168.1.100:9096")
with Run(device) as run:
login = run.assert_unique(device.selector().name("login_button"))
run.step("open_login", login.click, capture_after=True)
完整可运行的带注释示例见 examples/完整流程示例.py 与从零开始使用教程第 10 节。
Inspector 与真机验收
ut inspect 会启动仅监听本机回环地址的浏览器 Inspector。界面展示当前截图、控件树、前台 App、控件属性、可复制选择器和真机坐标;“框选区域”会冻结一张原始 PNG 并暂停实时刷新,确认后保存无损裁剪图及同名 JSON 元数据。
| 我要改的 | 参数 | 默认值 |
|---|---|---|
| 连接哪台手机 | 全局 --device HOST[:PORT],或配置文件 device.address |
配置文件 / 127.0.0.1:9096 |
| Inspector 自己监听在哪 | inspect --host HOST |
127.0.0.1 |
| Inspector 监听端口 | inspect --port PORT(0 表示随机端口) |
0 |
| 不自动打开浏览器 | inspect --no-browser |
自动打开 |
不要使用 --host 0.0.0.0。 Inspector 的 /api/* 接口没有任何鉴权,能读取设备截图与控件树;绑定到非回环地址等于把手机屏幕内容暴露给同网段所有主机。
部分 App 或页面不暴露无障碍控件树,此时 Inspector 会正确显示没有语义节点;仍可单独使用截图、OCR、图色与坐标操作。
真机冒烟测试使用独立配置文件,避免环境变量和误操作:
copy tests\integration.example.json tests\integration.json
edit tests\integration.json
py -m unittest discover -s tests -p test_integration.py -v
将 tests\integration.json 的 enabled 显式设为 true 后才会连接真机。该套件默认只读取状态、截图、控件树、日志端口和可选选择器,不执行点击、输入、上传、删除或部署。
运行方式与边界
CLI 有三种等价调用:ut(默认缩写)、uitap(全名)、py -m uitap(不依赖 PATH,Windows 推荐)。除模板匹配所需的 Pillow(以及可选的 OpenCV 加速)外,该库只依赖 Python 标准库。生产发布前应在目标 App、目标 iOS 版本和目标设备上执行集成验收;已知的设备端兼容降级见生产使用指南。
Release files for uitap 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| uitap-0.1.0.tar.gz | 123.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| uitap-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 235.2 kB
Release files / uitap-0.1.0.tar.gz
| Download URL | uitap-0.1.0.tar.gz |
|---|---|
| Size | 123.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ca77c13c31e5d8cb4599af953ef36a7e70a13faf82bf9ff775c7950f39afa632
|
|
BLAKE2b-256 checksum How to use checksums |
6b20ac26942afb66e16b9e27102d048713d92943709e60d3e9f243467ed7e588
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / uitap-0.1.0-py3-none-any.whl
| Download URL | uitap-0.1.0-py3-none-any.whl |
|---|---|
| Size | 111.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9a230fae2de140695a272aed78e049cf0935500b407034cc936549dbafc83feb
|
|
BLAKE2b-256 checksum How to use checksums |
5fcfec274af3f2f6488cd316fee3ccc0456914ebb03719e7b1a4ff0a75b8325d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency log