diff --git a/.claude/skills/phone-adapt/references/verification.md b/.claude/skills/phone-adapt/references/verification.md index 811b0fa..84f417a 100644 --- a/.claude/skills/phone-adapt/references/verification.md +++ b/.claude/skills/phone-adapt/references/verification.md @@ -6,12 +6,12 @@ ## 环境 ```bash -~/Library/Android/sdk/emulator/emulator -list-avds # Medium_Phone_API_36.1(手机) / Aerologic_Tablet(平板) +/opt/homebrew/share/android-commandlinetools/emulator/emulator -list-avds # 本机现仅 AeroLogic_Phone(手机) adb devices -l adb -s shell wm size && adb -s shell wm density ``` -判定形态:手机 1080×2400@420dpi → `PHONE(sw=411dp)`;平板 1280×800@160dpi → `TABLET(sw=800dp)`。 +判定形态:手机 720×1440@292dpi → `PHONE(sw≈394dp)`;平板 1280×800@160dpi → `TABLET(sw=800dp)`(本机平板 AVD 待建,见文末工具选型纪要)。 `ui_probe.sh` 封装了常用操作,比手写 adb 省事且更可靠: @@ -46,7 +46,7 @@ adb -s install -r -d app/build/outputs/apk/debug/app-debug.apk adb -s shell monkey -p com.lukouguoji.aerologic -c android.intent.category.LAUNCHER 1 ``` -测试环境账号在记忆文件 `test-env-login.md`(ADMIN / 用户已授权保存),可自主登录。 +测试环境账号在记忆文件 `aerologic-test-account.md`(本机,admin / 用户已授权保存;旧机器文件名为 `test-env-login.md`),可自主登录。 填表用 `input text`,**`#` 不需要转义**——新版 adb 的 input text 参数不经远端 shell 解析, 写 `\#` 反而会把 `\` 也输进去(实测多出一位)。 @@ -179,3 +179,88 @@ adb -s logcat -d -s DBG | grep -A14 "'旧值' -> ''" | grep "at com.luk 本次靠这招定位到 `TextView.onRestoreInstanceState → EditText.setText → doOnTextChanged`, 即复合自定义 View 的 id 串档(见 `components.md`)。**排完删日志。** + +--- + +## 工具选型纪要:ADB(ui_probe.sh) × Mobile MCP 分工(2026-10-02) + +背景:`mobile-mcp`(`@mobilenext/mobile-mcp`)已装入项目级 `.mcp.json`,与本手册的 +ADB/ui_probe.sh 流程并存。以下基于 2026-10-02 在 `AeroLogic_Phone` 模拟器上的实测对比 +(登录流程实测到“填表”一步,因内网不通放弃后续),给出后期开发的工具选择规则。 + +### 能力对照(只列有差异的维度) + +| 维度 | ADB + ui_probe.sh | Mobile MCP | +|------|-------------------|------------| +| 元素定位 | `tap-text` 按文字点,**每次点击前重新 dump**,天然抗布局变化;同名多处可指定序号 | 按 ref 点,键盘弹出/页面导航后 **ref 失效**,必须重新 list(实测踩过) | +| 元素读取 | `texts` 只出可见文字,token 便宜,配 grep 断言(`texts \| grep -c "全选"`) | 完整控件树(text/id/类型/focused/disabled/checked/坐标),信息全但 **token 重**(登录页 54 行) | +| 文本输入 | `input text` + `keycombination`(CTRL+A/DEL 清空——登录 bcrypt 回填坑的标准解法) | `type_keys` 只能输入,**无清空原语**(实测需回落 adb) | +| 请求核对 | `req <关键字>`(OkHttp 多行 pretty JSON 按关键字截取,为本项目定制) | `get_device_logs` 可过滤 tag/进程,多行报文截取不如 `req` 顺手 | +| 崩溃检查 | `crash` | `list_crashes` / `get_crash`(等价) | +| 前台断言 | `dumpsys activity`(手写 grep) | `get_foreground_app` 一次调用 | +| 录屏 | `adb shell screenrecord`(手拉文件) | `start/stop_screen_recording` 直接回传路径,更省事 | +| 批量操作 | 脚本串联,每条一次往返 | `mobile_batch_commands` 一次往返多步(**页面稳定时**才高效) | +| iOS / 云真机 | 无 | 有(本项目 Android-only,暂无用武之地) | +| 依赖 | 零依赖(本机 adb 即可) | npx 每会话冷启动、Node 20+、`@latest` 有版本漂移风险(建议固定 `@1.0.7`) | + +### 选型规则(后期开发按此执行) + +**默认走 ADB + ui_probe.sh**。本手册全部流程不变:构建安装、冷启动/直启、登录、 +wait-text 就绪等待、tap-text 交互、texts 断言、req 抓包、crash 归零、方向采样、Pad 回归、 +样例 Bean 注入。理由:为本项目的坑定制(bcrypt 回填、Loading 吞点击、参数名 A/B)、 +token 成本低、零外部依赖,且 tap-text 每次重新 dump,比 ref 更抗布局变化。 + +**以下四种场景切 Mobile MCP**: + +1. **控件级语义断言**——要看 disabled/checked/focused 状态、控件 id、输入框变换后的值 + (如“密码框 9 个点”“角色 Spinner 是否禁用”“用户名框自动大写成 ADMIN”)。元素树比 + 截图肉眼判读可靠,比 `texts` 信息全。实测:登录页一次拿到 `inputPass text="•••••••••"`、 + 角色 Spinner `disabled`,这类断言 `texts` 做不到(密码框无明文文字) +2. **页面稳定时的多步连续输入**——list 一次拿 ref,`batch_commands` 一次往返完成 + tap→type→tap→type;比逐条 adb 省 round-trip。前提:中间不弹键盘收不起/不导航 + (弹了就见下方回落规则) +3. **录屏取证**——复现“先横屏闪 1 秒”类**时序 bug**,mp4 归档进问题清单,比连拍截图省力 +4. **前台应用/安装卸载等状态核查**——`get_foreground_app`、`install/uninstall/launch_app` + 一步到位,省得记 dumpsys/am 语法 + +**回落规则(两者随时可混用,操作同一设备无状态冲突)**: + +- mobile-mcp ref 失效(键盘弹出/导航后点击落空)→ 重新 `list_elements`,或直接换 + `ui_probe.sh tap-text`(按文字,永远新鲜) +- 需要清空输入框(登录 bcrypt 回填)→ 只能 adb:`input keycombination 113 29` + DEL +- 多行请求/响应体核对 → `req`,不用 mobile-mcp 的日志过滤硬凑 + +### 实测踩坑(Mobile MCP,2026-10-02) + +- ⚠️ **键盘弹出会平移布局**:之前 list 出的 ref/坐标失效。batch 里连续 click+type 会把 + 两段文本打进同一个框(用户名框变成 `ADMINAA123456#`)。规避:每步输入完先 + `KEYCODE_BACK` 收键盘再点下一个目标;或点完先确认焦点再 type +- 无“清空字段”原语;`type_keys` 输入即所得,不会帮你选中文本 +- 元素树 token 开销大,断言优先 `texts | grep`,确实要看状态/id 才上 list_elements + +### 本机环境更新(2026-10-02) + +- SDK 根目录:`/opt/homebrew/share/android-commandlinetools`(brew 安装,emulator 包已装) +- 手机 AVD:`AeroLogic_Phone`——720×1440、5.51 寸 292dpi(sw≈394dp,落手机桶 360~411dp)、 + Android 12 / API 31(与 targetSdk 一致)、arm64 纯 64 位(本项目无 abiFilters,唯一含 + .so 的 fimage.aar 自带 arm64-v8a,兼容)、无边框(`showDeviceFrame=no`) +- ⚠️ **旧文档里的 `Aerologic_Phone_5.5_API31`(300dpi/sw=384dp)、`Medium_Phone_API_36.1`、 + `Aerologic_Tablet` 均为旧机器 AVD,本机不存在**。平板回归前需先建平板 AVD + (1280×800@160dpi,`avdmanager create avd` 后照本文「Pad 端回归」执行) +- 启动:`/opt/homebrew/share/android-commandlinetools/emulator/emulator -avd AeroLogic_Phone` + (Quick Boot 快照已存在,二次启动数秒就绪) +- 模拟器 NAT 出网,**内网服务不可达**(本次登录实测“服务器不通”而放弃)——需要真实接口 + 联调时先确认宿主机网络可达内网;不可达时按上文「无数据时怎么核对 UI」注入样例 Bean +- `.mcp.json` 已加 `mobile-mcp` 条目(npx stdio),**建议把 `@latest` 固定为 `@1.0.7`**; + 该文件 git 跟踪,改动需提交后队友才可用 + +### 推荐配合模式(单页验证的完整动线) + +adb 骨架 + mobile-mcp 点睛,一条龙: + +1. **adb**:构建安装 → 冷启动/直启(`am start`)→ 按登录节填表(含 bcrypt 清空顺序) +2. **ui_probe**:`wait-text` 就绪 → `tap-text` 交互 → `texts | grep` 断言 → `req` 抓包 → `crash` 归零 +3. `texts` 断言不够(要看状态/id/变换值)或要连续多步输入 → **mobile-mcp**: + `list_elements` → `batch_commands`(tap/type) +4. 时序类 bug(闪屏/动画/异步错位)→ **mobile-mcp 录屏**取证,问题清单贴 mp4 + 截图 +5. 全程崩溃检查两家等价(`crash` / `list_crashes`),任选 diff --git a/.mcp.json b/.mcp.json index e5ee220..afb6122 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,5 +1,9 @@ { "mcpServers": { + "mobile-mcp": { + "command": "npx", + "args": ["-y", "@mobilenext/mobile-mcp@1.0.7"] + }, "api-doc": { "type": "http", "url": "https://www.agentfoxapp.com/mcp/976caff7-5f98-4487-bccf-3aa20c92cf1f",