用agent-device开展跨端AI测试
文章介绍为Flutter应用选择agent-device的依据、Claude Code安装方式与基本操作循环,并提示Flutter测试中的注意事项。选型比较涵盖双平台支持、固定流程回归及测试证据交接等需求。
AI 深度解读
让 AI 操作手机 App,难点不只是点中按钮,还包括确认操作成功、保存执行证据,以及把跑通的流程交给后续回归。作者为 Flutter 应用选择了 Callstack 的开源工具 agent-device,看中的是 iOS、Android 双平台覆盖,以及流程保存和回放能力。
这篇记录基于 agent-device 0.21.31(2026-10-24),提供了一条从安装到操作设备的入门路径。最有用的部分,是它指出了几个容易被演示效果掩盖的问题:截图不能代替断言,元素引用会失效,Flutter 的 Key 也不能直接拿来定位。
为什么选择 agent-device,而不是其他方案
Flutter 一份代码覆盖 Android 和 iOS,测试工具也得覆盖两端。作者最先考虑的 Google Artemis 只支持 Android,iOS 尚在路线图上,因此没有满足需求。
其余候选工具的区别,主要在于「能操作」之后能留下什么:
- mobile-mcp 通过 MCP 提供双平台点击、截图和无障碍树,但没有会话、回放和证据存储能力,作者认为不便把已验证流程交给 CI。
- Maestro 用 YAML 固定 E2E 流程,也提供 MCP server,更适合重复执行确定的路径。
- Arbigent 建在 Maestro 之上,但其作者给出的速度评分为 1/5、可靠性为 3/5,YAML 格式也还在变化。这是项目作者自评,并非本文的横向测试。
- Drizz、Minitap 等商业服务整合了真机设备池与自然语言 Agent,但作者只能找到厂商材料,无法核实成本和质量。
agent-device 的文档明确声明支持 Flutter,同时覆盖 iOS、Android 的模拟设备和真机。它提供 CLI、MCP server,能把验证过的流程保存为 .ad 脚本,也能导出 Maestro YAML,采用 MIT 许可证。
这些条件解释了作者为什么选它,但还不能证明它跑得更快、更稳。
从安装到操作,关键是每一步都有可检查的结果
安装入口是全局 CLI,然后检查环境:
npm i -g agent-device@latest
agent-device doctor
要注意第一行使用了 @latest,它不会固定在本文记录的 0.21.31。doctor 检查连接设备、工具链和开发服务器状态;作者这次检查通过,仅对未使用的 HarmonyOS、Vega 平台给出警告。
接着用 claude mcp add -s user agent-device -- agent-device mcp 注册到 Claude Code。-s user 表示用户级配置,各项目都能使用。
仓库还提供 agent-device、ios-simulator、android-emulator 三个 skill。官方安装命令是 npx skills add callstack/agent-device,但作者遇到 Claude Code auto mode 安全检查阻止执行,于是克隆仓库,将 skills/ 下三个目录复制到 ~/.claude/skills/。这是作者环境里的安装经历,不代表所有环境都会遇到。
下面这组命令展示了准备设备、打开应用、操作、验证和关闭的完整顺序:
agent-device boot --platform android --device "<emulator name>" --headless
agent-device install /absolute/path/app-debug.apk --platform android --device "<emulator name>"
agent-device open <bundle-id> --platform android --device "<emulator name>" --foreground
agent-device press @e5 --settle
agent-device fill @e11 "text" --settle
agent-device wait text "<expected text>"
agent-device screenshot /absolute/path/home.png
agent-device close
重点看 wait text 那一行:它检查预期文字是否出现,后面的截图只负责留证。也可以使用 wait <selector> 验证目标元素。
open 会读取屏幕,为元素返回 @e5 这样的引用。press、fill 加上 --settle 后,会等待界面稳定并返回变化部分,方便 Agent 决定下一步。不过,屏幕变化后旧引用可能失效,应该从最新返回的差异里重新选目标。
另一个容易踩的坑是安装路径。install 的相对路径按 agent-device daemon 的工作目录解析,可能报出 App binary not found,因此应使用绝对路径。
需要卸载时,执行 claude mcp remove agent-device -s user、npm uninstall -g agent-device,并删除三个 skill 目录。
Flutter 能不能测,取决于控件是否能被读到
Flutter 侧先构建安装包:iOS 模拟器使用 flutter build ios --simulator --debug,Android 使用 flutter build apk --debug。
但安装成功,并不代表所有控件都能定位。agent-device 通过无障碍树读取屏幕,也就是系统提供的一份界面元素描述,而不是直接读取 Flutter 的 widget 树。
按原文描述,默认主要能读到带文字的 widget;图标按钮和容器不会自动提供可用信息。需要给这些控件补上 Semantics(identifier:) 或 semanticLabel。Flutter 的 Key 不会出现在无障碍树里,不能直接充当这里的定位标识。
文字定位还有语言问题:设备语言变了,无障碍树里的标签也会跟着变化。因此,跨语言回放更适合依赖 identifier。
作者还观察到,iOS 上的 AdMob 测试横幅会产生 platform_view、webview、link 节点。回放脚本的选择器应避开这些广告节点,减少误匹配。
我的判断
我认同作者把双平台支持、明确断言和流程回放放在选型前面。一次自然语言操作能跑通,只说明这次操作成功;能够重复验证的流程,才更接近日常回归的需求。
但原文没有提供成功率、执行耗时、重复运行次数,也没有展示 .ad 保存、回放或导出 Maestro YAML 的具体过程。因此,工具能力可以作为选型依据,稳定性判断目前仍是经验之谈,不能据此认定它优于 Maestro。
对于流程固定、目标是持续回归的团队,Maestro 仍有直接价值;需要 Agent 探索页面,再考虑固化路径的团队,才更贴近作者选择 agent-device 的理由。另外,团队得有条件补齐 Flutter 的语义信息。界面缺少可定位元素时,换一个 Agent 未必能解决问题。
能拿来做什么
- 给 Flutter 项目补测试入口时,先检查关键图标按钮的无障碍信息,为需要稳定定位的控件补充 identifier,不要只添加 Key。
- 用 Claude Code 操作 App 时,把每个关键动作后的
wait text或wait <selector>写进流程,并从最新界面差异里获取元素引用。 - 在接入 CI 前,先选一条短业务路径,验证
.ad回放或 Maestro YAML 导出是否满足需求;原文尚未证明这部分在实际流水线中的可靠性。 - 整理本地复现步骤时,记录 agent-device 版本、设备语言和安装包绝对路径,避免
@latest、标签翻译或路径解析让复现条件发生变化。