让 Agent 操作手机 App,最直观的做法是截屏、看按钮位置、点击坐标。但截图里的 (x, y) 不一定是设备接受的点击坐标:图片可能被缩小,iOS 的屏幕尺寸还可能用 points 而非截图像素表示。另一个选择是读取原生界面元素,按元素引用点击。该怎么选?
我读了 mobile-next/mobile-mcp 的 固定源码版本。它的选择顺序很明确:优先拿当前屏幕的元素列表;目标不在元素树里,或需要判断视觉外观时,再看截图。 这篇是源码导读,未连接手机或模拟器,不报告点击成功率。
元素列表给 Agent 的不只是一个位置
mobile_list_elements_on_screen 会从设备读取元素,再输出可用的引用、类型、文字或无障碍标签、坐标和尺寸;部分元素还带有选中、勾选、禁用等状态。和只看一张图片相比,Agent 可以用标签判断目标,也能在点击前看到元素是否被禁用。具体字段与格式可看项目的 format-elements.ts。
同一个 MCP 点击工具同时接受 ref 或 (x, y)。在这版 server.ts 中,只要提供 ref,它就优先调用 tapByRef;未提供 ref 时才检查两个坐标是否齐全。底层 MobileDevice 把该引用传给 mobilecli 的 io tap。因此,对元素列表里清楚标出的按钮,源码支持“读元素 → 取当前 ref → 点击”的路径。
这里有两个容易忽略的限定。第一,ref 来自最近一次界面读取。项目的工具说明要求在导航或布局变化后重新列元素;不能把上一个页面的 ref 当成长期稳定的按钮 ID。第二,tapByRef 是可选的 robot 能力;如果走不支持它的旧后端,点击工具会明确报“legacy robot mode 不支持按 ref 点击”。“项目有 ref 参数”并不意味着每一种运行后端都能用它。
目标不在元素树里,才回退到截图
原生界面树不一定暴露屏幕上所有可见目标。项目的 Robot 接口 对元素读取标注了“原生 App,非 WebView”的范围;项目给 Agent 的指令也把截图定位留给元素层级缺失或需要判断视觉外观的情形。这是该提交的接口和提示设计,不等于所有 WebView 在所有设备上都完全不可观察。
截图回退还有一个坐标陷阱。mobile_take_screenshot 可能返回缩小后的图;coordinate-mapping.ts 读取截图尺寸与设备屏幕尺寸,计算横纵方向的换算比例,再把“图上坐标要乘几倍”写进工具结果。如果两边尺寸相同,则说明坐标一致;尺寸未知时不输出换算建议。
源码里的单元用例包含两种很能说明问题的输入:截图 590×1278、屏幕 1179×2556 时,横纵倍率约为 1.998 和 2;iOS 截图 1179×2556、屏幕 393×852 时,倍率都是 0.333。这些是代码中测试用的尺寸和预期值,不是我对真实设备做出的测量。直接把截图中看到的 (300, 500) 交给屏幕点击接口,只有在坐标系一致时才有依据。
怎样决定下一步
从这份实现中,我会提炼出一个有限的操作顺序:
- 先列出可用设备,选定设备 ID;每次工具调用都传同一个设备 ID。
- 读取当前屏幕元素;如果目标有明确标签和 ref,并且后端支持 ref,就用当前 ref 点击。
- 点击导致导航或布局变化后,重新读取元素,不沿用旧 ref 或旧坐标。
- 目标不在元素树里,或任务需要判断颜色、图像、排版时,再截屏。点击前先看工具给出的截图到设备坐标换算。
- 元素与截图都无法唯一定位时,停下补充观察条件,不凭猜测点一个近似位置。
这不是“元素方式一定比视觉方式稳定”的实测结论,而是该项目在源码里明确实现的两条定位路径及其边界。本机这次没有已启动的 iOS 模拟器,当前环境也找不到 adb;我没有运行 mobile-mcp 的设备流程或它的测试。若要把它用于真实 App 验收,下一步应在指定设备上分别测试元素可见性、WebView、截图缩放和页面切换后的定位,而不能把源码具备某个入口直接当成任务已跑通。