好的,阿杰 — 我把 Android 自动测试工具 monkeyrunner 的进阶用法、环境准备、API 核心示例、实战脚本、常见坑与替代方案都给你整理成一份实战手册。必要的要点我附上官方/社区来源作参考。开始吧。


🐒 monkeyrunner 全面实战手册(中文)

简短结论:monkeyrunner 是 Android SDK 提供的一个基于 Python(Jython)的设备自动控制 API,可以安装应用、启动 Activity、发送按键/触摸事件、截屏并把截图拉回本地,适合做简单的 UI 自动化 / 回归 & 嵌入式自动化脚本。但它是基于 Jython 的老工具,社区维护较弱,生产环境更常用的替代方案包括 UIAutomator / Espresso / Appium 等。官方文档可参考。(Android Developers)


1)适用场景 & 优缺点(简明)

  • 适合:设备层、功能级的自动化(安装 apk、启动 Activity、简单 UI 操作、截屏比对、脚本化测试流程)。(Android Developers)
  • 优点:无需在 Android 应用内嵌测试代码、可在工作站以 Python 脚本驱动多台设备、能做截图对比与简单回归。
  • 缺点:基于 Jython,无法直接使用 CPython 原生扩展;SDK 里该工具维护不活跃,功能上被更现代框架替代(Espresso/UIAutomator/Appium)。建议只做轻量自动化或作快速原型。(Waldo)

2)环境准备(step-by-step)

  1. 安装 Android SDK(需要包含 platform-tools 与 tools/tools/bin)。
  2. 确认 monkeyrunner 命令可用(通常 Android SDK 的 tools/bin 或旧版 tools 下有此脚本):monkeyrunner --help
  3. 设备/模拟器通过 adb devices 可见并处于可控制状态。
  4. 注意:monkeyrunner 使用的是 Jython,所以脚本在 Jython 环境运行(某些 Python 标准/第三方库不可用)。(Android Developers)

3)核心 API(常用类/方法速览)

  • MonkeyRunner:静态工具方法(如 sleep()waitForConnection())。
  • MonkeyDevice:代表一台设备,主要方法:
    • waitForConnection(timeout, deviceId):连接设备。
    • installPackage(apkPath) / uninstallPackage(pkg)
    • startActivity(component='com.pkg/.MainActivity', extras=None)
    • touch(x, y, type):在屏幕(x,y)位置触摸。type 常用 'DOWN_AND_UP'
    • drag((x1,y1),(x2,y2),duration,steps):拖动手势。
    • press(keycode, type):发送按键事件(如 KEYCODE_BACK)。
    • type(text):输入文本(注意某些权限/焦点问题)。
    • takeSnapshot():截屏,返回 MonkeyImage 对象。
  • MonkeyImage:处理截图,可 getSubImage()writeToFile(),也可以做像素级比较(简单)或保存为文件。(Android Developers)

4)最小可运行示例(安装 APK、启动、点击、截屏并保存)

把下面保存为 simple_test.py,在 SDK 主机上运行 monkeyrunner simple_test.py

# simple_test.py
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

# 1) 连接设备(等待 10 秒),deviceId 可用 adb devices 列出
device = MonkeyRunner.waitForConnection(10.0, "emulator-5554")
if not device:
    raise SystemExit("设备未连接")

# 2) 安装 APK(若已安装可跳过)
apk_path = "/path/to/app-debug.apk"
device.installPackage(apk_path)

# 3) 启动 Activity(包名/Activity)
component = "com.example.myapp/.MainActivity"
device.startActivity(component=component)

# 4) 等待 UI 稳定
MonkeyRunner.sleep(2.0)

# 5) 在坐标 (300, 800) 点击(坐标按设备分辨率设置)
device.touch(300, 800, "DOWN_AND_UP")
MonkeyRunner.sleep(1.0)

# 6) 截图并保存到主机
result = device.takeSnapshot()
out_file = "/tmp/myapp_snapshot.png"
result.writeToFile(out_file, "png")
print("截屏已保存到", out_file)

运行:

monkeyrunner simple_test.py

注意:坐标系以设备屏幕为准,分辨率/密度不同需要设计相对坐标(百分比或查询屏幕宽高后计算)。


5)进阶脚本:元素查找(基于像素/图像匹配)与容错重试

monkeyrunner 没有像 Appium 那样的元素定位 API(xpath/id),常见做法是通过截图 + 图像匹配或颜色像素判断 UI 是否进入期望状态。示例(用子图匹配):

# image_match.py
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage

device = MonkeyRunner.waitForConnection()
device.startActivity(component="com.example/.MainActivity")
MonkeyRunner.sleep(1)

# 截全屏
screen = device.takeSnapshot()
screen.writeToFile("/tmp/full.png","png")

# 载入参考图(要提前准备)
target = MonkeyRunner.loadImageFromFile("/home/user/templates/button_ok.png")

# 查找 target 在 screen 中的位置(简单示意,API 在不同 SDK 版本可能差异)
found = screen.contains(target)
if found:
    print("找到了按钮")
else:
    print("没找到,重试或报错")

说明:官方的 MonkeyImage 支持一些基本图像方法,但并不如 OpenCV 强大。要做更精确匹配,通常在工作站端用 OpenCV 对保存的截图进行比对(先 writeToFile,然后用 Python/OpenCV 分析)。记住,Jython 环境下不能直接用 CPython 的 OpenCV 扩展,所以常用“保存截图 → 用外部脚本(CPython)比对 → 基于结果决定下一步”的混合方案。


6)常见实战技巧 & 注意点

  1. 坐标策略:不要写死像素坐标,建议先 device.getProperty('display.width')/display.height(部分平台可取),或基于 UI 元素的相对位置计算。
  2. 等待与重试:UI 响应有延迟,所有关键操作后加 MonkeyRunner.sleep() 或轮询截图判断状态。
  3. 日志print() 会输出到控制台,生产脚本建议把步骤/异常写到文件。
  4. Jython 限制:第三方 CPython 模块(如 numpy、opencv-python)不可直接 import;若需复杂图像处理,采用“保存截图 → 用主机 Python 脚本处理”方式。
  5. 并发设备:要同时驱动多台设备,可为每个设备启动独立的 monkeyrunner 进程并用不同 deviceId。
  6. 可靠性:monkeyrunner 的稳定性受 SDK 版本影响(有时启动会报 SWT/路径错误),遇到问题检查 SDK/tools 目录结构与脚本头部。(Stack Overflow)

7)构建更完整的测试流程(示例)

  • 流程:安装 → 清数据 → 启动 → 登录(截图比对 / OCR)→ 执行功能用例 → 收集日志(logcat)→ 截图 → 卸载(可选)
  • 结合 adb logcat:在脚本中并行启动 adb logcat(shell)收集日志,便于回放与定位崩溃。
  • 报告:每次运行生成目录 results/<timestamp>/,保存截图、logcat、脚本输出,便于回溯。

8)替代方案(何时不用 monkeyrunner)

  • UIAutomator / Espresso:系统原生、维护活跃、定位元素稳定(推荐用于白盒/集成测试与 UI 元素交互)。官方 Test 库更加现代且高效。(Android Developers)
  • Appium:跨平台、支持多语言、社区活跃,适合覆盖复杂的 UI 自动化和云设备 farm。
  • Monkey (UI/Application Exerciser Monkey):与 monkeyrunner 不同,是在设备侧产生随机事件来做压力测试(不是脚本 API)。要区分两者。(Stack Overflow)

9)常见问题与解决办法

  • monkeyrunner 无法启动 / 报 SWT 错误:检查 monkeyrunner 启动脚本中 frameworkdir 指向是否正确(历史问题见 StackOverflow),或 SDK 版本路径变化导致的 jar/依赖缺失。(Stack Overflow)
  • 图像比对误判:尽量使用模板匹配的阈值、灰度比较或对关键区域做比较,避免整体像素严格匹配。
  • 无法输入文本:确保输入框已获取焦点;在某些情况下需要先 device.press('KEYCODE_TAB','DOWN_AND_UP') 或调用 startActivity 并等待。
  • 设备分辨率适配:在多分辨率测试时,建议用相对坐标或为设备分辨率单独准备模板。

10)实践示例集(收尾,2~3 个常用脚本模板)

A. 批量设备并行化运行(shell 启动多个 monkeyrunner)

for dev in emulator-5554 emulator-5556 device_serial_1; do
  monkeyrunner run_test.py $dev > logs/$dev.log 2>&amp;1 &amp;
done

run_test.py 中通过 waitForConnection(timeout, sys.argv[1]) 获取设备。

B. 失败回收策略(伪代码)

  • 每个步骤封装 try/except,失败时截图 + adb bugreport + 重启应用或设备(如必要) → 标记用例为 FAIL → 继续下一用例。

11)参考资料(官方 & 社区)

  • 官方 monkeyrunner 文档(API & 概念)。(Android Developers)
  • 社区与博客:关于是否继续使用 monkeyrunner、替代方案讨论(Appium/UIAutomator/Espresso)。(Waldo)

✅ 小结(你现在能做的事)

  • 使用 monkeyrunner:快速写脚本(安装、启动、点击、截屏、保存),适合设备级快速回归或制作自动化演示。
  • 若需更稳定、元素级定位、易于维护的自动化测试,优先考虑 Espresso / UIAutomator / Appium