🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

安卓直控 BBZ-bob/dsh-quick-adb

DeepSeek Harness
BBZ-bob3 天前有提交已提供中文文档扫描:含敏感能力

用控件树定位操作安卓手机,免截图识图提速

30.6/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/2 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add BBZ-bob/dsh-quick-adb
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么[目录]—
dsh 原生插件 · ui
暂无时间戳·判据 →
装得上吗[实装验证]—
本站尚未做安装检查
暂无时间戳·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 3 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 19 处,展示前 19 条)
  • 执行外部命令来自配置/变量
    lib/adb.js:58
    child = spawn(this.adbPath, argv, { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
  • 写入本地文件
    lib/engine.js:212
    mkdirSync(shotDir, { recursive: true });
  • 写入本地文件
    lib/timing.js:59
    await mkdir(dirname(this.file), { recursive: true });
  • 读取本地文件
    lib/timing.js:63
    const info = await stat(this.file);
  • 写入本地文件
    lib/timing.js:65
    await rename(this.file, this.file + '.1');
  • 写入本地文件
    lib/timing.js:69
    await appendFile(this.file, line, 'utf8');
  • 读取本地文件
    lib/timing.js:169
    async readFile({ limit = 500 } = {}) {
  • 读取本地文件
    lib/timing.js:173
    const raw = await readFile(this.file, 'utf8');
  • 写入本地文件
    lib/timing.js:196
    await writeFile(this.file, '', 'utf8');
  • 读取本地文件
    lib/perceive.js:85
    const raw = await readFile(file, 'utf8');
  • 写入本地文件
    lib/perceive.js:130
    await mkdir(dirname(file), { recursive: true });
  • 写入本地文件
    lib/perceive.js:131
    await writeFile(file, JSON.stringify(this.deviceStore, null, 2), 'utf8');
  • 写入本地文件
    lib/vision.js:28
    await mkdir(dir, { recursive: true });
  • 写入本地文件
    lib/vision.js:33
    await writeFile(file, buffer);
  • 读取本地文件
    lib/vision.js:45
    bytes = (await stat(file)).size;
  • 执行外部命令来自配置/变量
    lib/vision.js:65
    child = spawn(command, {
  • 读取本地文件
    lib/vision.js:190
    const names = (await readdir(dir)).filter(name => name.startsWith('screen-') && name.endsWith('.png'));
  • 读取本地文件
    lib/vision.js:196
    items.push({ name, mtime: (await stat(join(dir, name))).mtimeMs });
  • 删除本地文件
    lib/vision.js:203
    await unlink(join(dir, item.name));
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/dsh-system-prompt@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(130 字)↓

给 dsh(DeepSeek Harness)的 Android 直控插件:用 uiautomator 控件树替代截图识图,把点击/输入/滑动/等待封装成 adb_* 工具,并按设备 dump 成本自适应合并往返。适用于需要按控件定位、每步看界面的手机自动化。

README

由 DeepSeek 最新模型翻译生成
dsh-quick-adb 给 dsh(DeepSeek Harness)加一条 Android 直控通道:用 uiautomator 的控件树替代整屏截图识图,把高频动作封装成可直接调用的 adb_ 工具,并把多步指令合并成一次 ADB 往返。 解决的问题很具体:dsh 部署在服务器上、通过 ADB 连手机,原来每一步都要「截图 → 模型识图 → 生成并执行代码」,单步稳定在 3–5 秒。装上本插件后,同一批动作的单步耗时降到 ~0.8 秒,ADB 往返从 2–3 次/步降到 1 次/步。 实测(node scripts/bench.mjs --steps 5,mock 设备,dump 520ms / 截图 480ms / 识图 2500ms / 生成代码 1200ms): | 路径 | 平均/步 | p50 | 往返/步 | 5 步总耗时 | | 旧:截图 → 识图 → 生成代码 → 执行 | 4241 ms | 4241 ms | 2.00 | 21.2 s | | 新:控件树 → 动作合并往返 | 833 ms | 833 ms | 1.00 | 4.2 s | 单步加速 ≈5.1×(多次运行 5.05–5.10;表内为单次示例,数值随调度略有波动)。
展开完整文档(README 剩余 1 节)
dsh-quick-adb

给 dsh(DeepSeek Harness)加一条 Android 直控通道:用 uiautomator 的控件树替代整屏截图识图,把高频动作封装成可直接调用的 adb_ 工具,并把多步指令合并成一次 ADB 往返。

解决的问题很具体:dsh 部署在服务器上、通过 ADB 连手机,原来每一步都要「截图 → 模型识图 → 生成并执行代码」,单步稳定在 3–5 秒。装上本插件后,同一批动作的单步耗时降到 ~0.8 秒,ADB 往返从 2–3 次/步降到 1 次/步。

实测(node scripts/bench.mjs --steps 5,mock 设备,dump 520ms / 截图 480ms / 识图 2500ms / 生成代码 1200ms):

| 路径 | 平均/步 | p50 | 往返/步 | 5 步总耗时 |
| 旧:截图 → 识图 → 生成代码 → 执行 | 4241 ms | 4241 ms | 2.00 | 21.2 s |
| 新:控件树 → 动作合并往返 | 833 ms | 833 ms | 1.00 | 4.2 s |

单步加速 ≈5.1×(多次运行 5.05–5.10;表内为单次示例,数值随调度略有波动)。自测(node scripts/selftest.mjs)里,9 个真实场景综合下来是 0.38 次往返/步,对照实测的「朴素三步式」是 3 次/步。

0. 真实链路实测(2026-11-01,由部署在云端的 dsh 自身经 QQ 通道复测)

上面的数字来自 mock 设备(dump 520ms)。真实链路上 dump 本身就要 2.4–2.5s,所以单步是 3 秒量级,不是 0.8 秒。下面是独立复测(阿里云 Debian + 荣耀平板 Android 16 + easytier 组网,RTT 125ms)的关键结论:

按「动作 + 取回界面」对齐(这才是插件的真实使用形态)

| 场景 | 裸 adb | 插件 | 往返 |
| 点一下并拿到新界面 | 3206 ms | 3040 ms | 4 → 2 |
| 滑一下并拿到新界面 | 3433 ms | 3142 ms | 4 → 2 |
| 冷缓存读界面 | 3013 ms | 2431 ms | 3 → 1 |
| 连续操作中读界面 | 3013 ms | ≈ 0 ms | 3 → 0 |
| 启动并看到界面 | 3442 ms | 3640 ms | 持平 |

固定坐标流水线(10 个动作,3 轮)

| 路径 | 动作合计 |
| 裸 adb 脚本 | 3729 ms |
| 插件逐步调用 | 4911 ms(慢 32%) |

原因不是感知慢,而是这条流程根本不需要感知:每一步多一层 Node 封装、各自拉起一个 adb 进程,而省下的往返没人用。整轮墙钟 37.3s 里 33s 是等界面渲染,1.2s 的差距被淹没。

结论:插件值钱的地方是「按文案定位 + 每步看界面再决定下一步」。录制好的死坐标流水线请直接用 adb_shell 或一条 adb_batch(合并成一次往返),不要逐步调工具。

P3e:0.2.5 达标(比裸 adb 快 19.8%)与随后的三处打磨

0.2.5 实测(同流程 3 轮):合计 7405ms vs 裸 adb 9232ms(−19.8%),「定位并点设置」5409 → 3054ms。三种 confirm 状态的探针:

| 模式 | 实测 | 说明 |
| confirm:auto(默认) | 3106 / 2832ms | 本机 dump 慢 → 自动不确认,等价最优 |
| confirm:true | 5584 / 5595ms | 强制确认,多一整遍 dump |
| confirm:false | 3214 / 3170ms | 只等待不解析 |

0.2.6 的打磨(对应复测提的三点):

1. 纯动作回退已修:auto 判定“不做确认”时,若调用方也没显式要求等待,就一并省掉那段 250ms sleep。此前 home 197→234、back 162→296 的差值正好是这次多余等待。
2. 设备画像按 serial 落盘(<dsh-home>/quick-adb/devices.json):dump 成本与模式重启后直接复用,不必重新估。
3. adb_timing 表头直接给结论:设备 dump ≈ 2640ms(serial …,模式 plain)|dump 偏慢:保持 confirm=auto,一眼看出这台机器值不值得开确认。

另修一处表头字段名错误:clickables 写成了复数,引擎读的是单数,导致界面摘要第一行永远显示「可点击=0」而下面却列着 N 个目标(P3f 现场发现)。同时统一了计数口径——节点级计数改名 clickableNodes 仅作诊断,所有对外展示一律用 目标=N(严格等于清单条数),不再出现两个数字打架。

启动类动作仍是唯一略慢于基线的项(550 vs 480ms):appSettle 默认已是 none,这点差值来自 Node 封装 + 一次 adb 进程启动,不是可省的 dump。

P3c:0.2.3 复测——compressed 修对了,但真瓶颈是「一次点击两次 dump」

| 步骤 | 基线 | 0.2.0 | 0.2.3 |
| 回桌面 | 286 | 353 | 232 |
| 返回 | 602 | 361 | 173 |
| 读界面 | 3367 | 2558 | 2721 |
| 启动 B 站 | 1079 | 1104 | 688 |
| 定位并点「设置」 | 3418 | 5345 | 5771 |
| 合计 | 9232 | 10283 | 10083 |

compressed 自动探测生效了(其余步骤全面转好),但定位点按没变:adb_tap(selector) 在这台设备上做两遍 dump(定位 2.7s + 确认 2.7s)。探针数据:settle=none 只要 2655/2991ms。

0.2.4/0.2.5 起:两件事分开处理。

- 插件测量本机 dump 成本,超过 slowDeviceDumpMs(默认 1500ms)自动进入「单 dump 模式」:动作只做定位 dump,不做事后确认,返回里注明「需要看界面时再调 adb_screen」。
- settle 只管等待,confirm 管是否重新解析(0.2.5 拆分)。P3d 现场脚本显式传 settle:'fast',以前会被迫多做一遍确认 dump;现在显式 settle 不再隐含确认。confirm:false = 只等待不解析,confirm:true = 强制确认,默认按本机 dump 成本自动决定。
- 代价要心里有数:慢 dump 设备上,每次确认约多花 2.5–2.7s(本机实测 dump 2.4–2.8s)。

按探针数据(settle=none 2848/2842ms),定位点按应回落到 ~2.85s,整轮约 6.9s,比裸 adb 快 ~25%。快 dump 设备行为不变。

P3b:为什么「定位点按」反而变慢(0.2.3 已修)

第三次复测(稳定界面 + 必须定位的步骤,3 轮均值):

| 步骤 | 基线 | 插件 0.2.0 | 说明 |
| 定位并点「设置」 | 3418 ms | 5345 ms | compressed 拖累 |
| 返回 | 602 ms | 361 ms | 缓存/少往返 |
| 读界面 | 3367 ms | 2558 ms | 少 2 次往返 |
| 合计 | 9232 ms | 10283 ms | +11%,但 ADB 调用 11 → 7 |

根因:该设备的 uiautomator dump --compressed 要 11.5s(直接超时),普通 dump 只要 2.3–3.7s。而 0.2.0 默认开 compressed。

0.2.3 起:默认 plain,dumpMode 可配;auto 下只有 plain 平均超过 slowDumpMs(默认 4s)才试一次 compressed(超时上限 3s),试完定死不再反复。按上述数据,定位点按应回落到 ~2.9s,整轮约 7.8s —— 比基线快约 15%(这一项是推算,等实测确认)。

同时修掉两个会导致脚本中断的问题:dump 超时不再抛错(批量降级执行、adb_wait 返回 ok:false)、perceive:false 提供纯动作快速通道。

0.2.2 补记:现场复测 swipe → swipe → dump 三步是 2 次往返 6434ms,其中第二次是收尾重复 dump(末尾已有 {dump:true},verify 又补了一次)。0.2.2 起收尾只在「上次 dump 后仍动过界面」时才补,同一流程变为 1 次往返(该链路上约省 3.2s)。因此批量里不需要在末尾再写 {dump:true}。

本节数据来自使用者部署在云端的 dsh 实例(经 QQ 对话驱动,设备为荣耀平板)。本轮据此修掉了 4 个问题:adb_batch 返回值不是 lossless JSON(导致 3/4 次调用直接报错)、dump 彻底失败时 adb_tap 不走视觉兜底、失败时换模式重试导致等待翻倍、adb_app 默认等待拖慢启动。详见 AUDIT.md 第 4 节。

当前版本 0.2.8(tag v0.2.8,可用 dsh plugin add "github:BBZ-bob/dsh-quick-adb#v0.2.8" 锁定安装)

文档索引:实测汇总 docs/RESULTS.md|变更记录 CHANGELOG.md|问题与修复 AUDIT.md|自检方法与可信度 docs/VERIFICATION.md|支持的环境 docs/ENVIRONMENTS.md|为什么能做到 docs/WHY-IT-WORKS.md

1. 它为什么快:三条主线

主线一:把「看图」换成「读结构」

uiautomator dump 直接给出控件层级、文本、resource-id、类名、可点击性、精确 bounds。同样的屏幕,截图是 1080×2400 的位图(要上传、要模型推理),dump 是几十 KB 的 XML(本地正则解析,毫秒级),结果确定性可复现——不需要模型猜坐标。

| 维度 | 截图 + 识图(旧) | uiautomator dump(本插件) |
| 单次耗时 | 截图 300–600ms + 模型推理 1–4s | 300–800ms,无模型参与 |
| 输出 | 位图,坐标靠模型估计 | 结构化文本 / id / 类名 / bounds |
| 可复现性 | 每次可能不同 | 同一界面完全一致 |
| 何时失效 | 基本不失效 | WebView / Flutter / 游戏 / DRM(自绘界面) |

失效场景由第 5 节的兜底阶梯接管,不是硬失败。

主线二:动作与「重新感知」合并成一次往返

朴素实现的一步是三条命令:

adb shell uiautomator dump /sdcard/ui.xml ← 往返 1 adb shell cat /sdcard/ui.xml ← 往返 2 adb shell input tap 540 1200 ← 往返 3 然后还得再 dump 一次才知道点完是什么界面 ← 往返 4、5

本插件把它压成一条:

adb shell "input tap 540 1200; sleep 0.25; uiautomator dump --compressed /sdcard/dsh_ui_x.xml >/dev/null 2>&1; cat /sdcard/dsh_ui_x.xml"

一次往返完成「点击 + 稳定等待 + 取回新界面」,返回值里直接带新界面的可点击目标摘要——所以模型下一步不需要再调 adb_screen。

主线三:同一界面内的重复读取走缓存

| 层级 | 条件 | 代价 |
| L1 精确命中 | 无动作发生 且 年龄 ≤ softTtlMs(800ms) | 0 次往返 |
| L2 探测复核 | 无动作发生 且 年龄 ≤ hardTtlMs(15s) | 1 次 ~110ms 的 dumpsys window |
| L3 重新解析 | 做过动作 / 过期 / 探测不符 | 1 次往返(dump + cat) |
| L4 视觉兜底 | 控件树不可用 / 定位失败 | 截图 + 可选视觉命令 |

任何会改变界面的动作都会把缓存标记为 dirty,下一次感知直接走 L3——绝不拿旧树去点新界面。动作本身已经顺带 dump 了新界面,所以这笔开销在实际运行中很少真的发生。

2. 安装

设备侧(服务器上)

adb start-server
adb connect 192.168.1.20:5555 # 无线调试;USB 直连可跳过 adb devices -l # 必须看到状态 device

方式 A:作为 bundle 装配(推荐)

把本目录作为包加入 profile(或从 npm / git 安装后启用 bundle) Web 侧栏 → Plugins 页安装并启用;具体子命令以 dsh plugin --help 为准

package.json 已声明:

"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }

cordis.patch.yml(顶层必须是 YAML 数组):

- insert:
- id: dsh-quick-adb
name: 'dsh-quick-adb'
config: { serial: '192.168.1.20:5555', settleFastMs: 200 }

方式 B:绝对路径手工挂载(不装包,服务器上最快验证)

在 profile 层 patch($DSH_HOME/profiles/<profile>/cordis.patch.yml)的既有 insert 块里加一条绝对路径:

- insert:
- id: dsh-quick-adb
name: /opt/dsh-plugins/dsh-quick-adb/lib/index.js
config:
serial: '192.168.1.20:5555'
settleFastMs: 200

lib/ 只有相对导入与 Node 内置模块,复制整个 lib/ + package.json 即可;@deepseek-ai/ 由宿主进程解析。

验证

node scripts/selftest.mjs # 95 项断言(装进 dsh 后另跑 22 项工具层断言,共 117)
node scripts/bench.mjs # 优化前后单步耗时对比

3. 文件结构

dsh-quick-adb/
├── package.json # dsh.bundle.patch;dshx.contributes.tools ├── cordis.patch.yml # bundle patch(insert) ├── README.md AUDIT.md ├── docs/ # 自检方法/环境/原理 ├── lib/ │ ├── index.js # 插件入口:name / inject / Config / apply │ ├── schema.js # schemastery 配置 + 独立默认值归一化 │ ├── adb.js # 低层 ADB 封装(一次 run = 一次往返) │ ├── xml.js # dump XML 解析(零依赖) │ ├── dump.js # 界面模型:标签、签名、可点击目标 │ ├── selector.js # 控件定位:评分 + 可点击性提升 + nth 越界报错 │ ├── cache.js # 单槽缓存 + L1/L2 判定计数 │ ├── perceive.js # 感知层:dump / probe / 分层复用 │ ├── actions.js # 动作执行器:唯一的「settle + dump + 失效」出口 │ ├── engine.js # 编排:定位、兜底、校验、公开动作 │ ├── batch.js # 批量编译:多步压成少量往返 │ ├── vision.js # 截图与外部视觉命令 │ ├── timing.js # 计时日志(JSONL)+ 聚合报告 │ ├── tools.js # 10 个 adb_* 工具(defineTool) │ ├── errors.js util.js ├── scripts/ # selftest / bench / mock-device └── fixtures/ # 三种真实形态的 dump XML

4. 工具清单

| 工具 | 作用 | 典型往返 |
| adb_screen | 读界面(可顺带定位一个控件,命中坐标写进返回文本) | 0–1 |
| adb_tap | 点击(selector 或数字坐标,支持长按) | 1 |
| adb_swipe | 滑动(方向 / 显式起止点 / 指定控件内) | 1 |
| adb_input | 输入文本(可定位、清空、回车提交) | 1 |
| adb_key | 返回/Home/回车/删除…,连按也只花 1 次 | 1 |
| adb_wait | 等元素出现/消失,或等界面稳定(idle) | 0–1/轮 |
| adb_batch | 批量执行多步,合并往返 | 1–2/批 |
| adb_app | 启动/停止/重启/清数据/查前台/查状态 | 1 |
| adb_shell | 逃生口(受 allowShell 控制) | 1 |
| adb_timing | 耗时与缓存命中报告 | 0 |

选择器统一是对象(传字符串等价于 {text}):

{"text": "设置"} {"textContains": "登录"} {"id": "btn_ok"} // 简写也能命中 com.foo:id/btn_ok {"cls": "Button", "nth": 1} // nth 越界会报错,不会静默取最后一个 {"text": "搜索", "clickable": true} 两个设计容易被忽略,但会显著影响命中率:

- 提升可点击性:文案节点常常 clickable=false(按钮 = 可点击容器 + 内部 TextView)。定位到文本后,向上找最近的可点击祖先,并跳过面积超过界面 70% 的「伪容器」。
- 评分而非首个命中:精确文案 > 包含 > 正则;自身文本 > 子孙聚合标签;同分取面积更小、层级更浅的节点。

5. 兜底阶梯(触发条件写死在代码里)

| 触发条件 | 处理 |
| 缓存年龄 ≤ softTtlMs 且无动作 | 直接复用(0 往返) |
| 缓存年龄 ≤ hardTtlMs、无动作、focus 探测包名/Activity 一致 | 复用并标记 cache-verified(1 次 ~110ms) |
| 做过动作 / 探测不一致 / 显式 invalidate | 完整 dump(1 往返) |
| dump 超时 | 本次改普通 dump 重试;不永久关闭压缩 |
| 设备不认识 --compressed | 永久降级为普通 dump |
| dump 返回空层级 | 重试一次;仍失败抛 dump-failed |
| 控件定位失败 | 强制重解析一次再试 |
| 重试后仍失败 | 截图;配了 visionCommand 就换算坐标继续点,否则报错附截图路径 |
| wait 超时 | 抛错并附「最后界面摘要」 |

visionCommand 是外部命令,stdout 返回 {"items":[{"text":"确定","x":540,"y":1820}]},插件据此算坐标。不配置时只落盘截图,把路径交回模型。

6. 批量指令 json {
"steps": [
{"tap": "搜索"}, {"wait": 200},
{"input": {"text": "hello world", "submit": true}},
{"waitFor": {"textContains": "结果"}},
{"swipe": "up"},
{"dump": true},
{"shell": "dumpsys battery | head -3"}
],
"verify": true
}

执行策略:先离线解析、再一次性下发——选择器先在缓存树上解析成坐标(0 往返),连续动作拼成一条 shell,只有「解析不了 / 需要看界面」时才切段插 dump,结尾一次 dump 同时充当「验证 + 下一步感知」。

往返账(selftest 实测,不是估算):

| 实现方式 | 往返/步 |
| 朴素三步式(dump / cat / input 各一次) | 3.00 |
| 本插件(综合 8 步场景) | 0.38 |

批处理还会按累计时长切段:整段脚本超过 actionTimeoutMs × 0.6 就提前分段,避免撞上超时被 kill、设备停在中间状态。

7. 配置项

| 配置项 | 默认 | 说明 |
| adbPath | $DSH_QUICK_ADB_BIN 或 $ANDROID_ADB 或 adb | adb 可执行文件 |
| serial | 空(自动选唯一设备) | 目标设备;多设备必填 |
| softTtlMs | 1500 | L1 复用窗口 |
| slowDeviceDumpMs | 1500 | 设备平均 dump 超过该值时,动作自动跳过确认 dump(单 dump 模式) |
| deviceCacheFile | <dsh-home>/quick-adb/devices.json | 设备画像(dump 成本/模式)缓存路径;留空则不落盘 |
| hardTtlMs | 15000 | L2 探测复核上限 |
| verifyProbe | true | 是否启用 L2 |
| dumpMode | auto | auto(先 plain,慢才试 compressed)/ plain / compressed |
| slowDumpMs | 4000 | auto 下 plain 平均超过该值才试 compressed |
| trialDumpTimeoutMs | 3000 | 试 compressed 的超时上限,避免一次试错等太久 |
| dumpTimeoutMs | 5000 | 单次 dump 超时 |
| actionTimeoutMs | 20000 | 动作脚本(含 sleep+dump)超时 |
| waitTimeoutMs | 10000 | adb_wait 默认超时 |
| settleFastMs / settleMediumMs / settleSlowMs | 250 / 700 / 1500 | 动作后的等待时长(只睡不解析;是否解析由 confirm 决定) |
| appSettle | none | adb_app 默认等待;none 只启动不取界面(实测启动慢 61% 的主因) |
| keyDelayMs | 80 | 连按按键间隔(原 200ms 让「返回两次」多花约 140ms) |
| inputFocusDelayMs | 80 | 点击输入框后到开始输入的等待 |
| skipDumpMs | 60000 | 判定「该界面不可 dump」后跳过重复尝试的时长 |
| skipDumpPatterns | 空 | 直接跳过 dump 的包名/Activity 正则,逗号分隔(如 tv.danmaku.bili) |
| stepDelayMs | 120 | 批处理中相邻盲动作间隔 |
| waitProbeFirst | true | 等待时先用轻探测判断界面切换 |
| probeFirstMaxMs | 1500 | 轻探测优先阶段上限 |
| inputMode | auto | auto / input / adbkeyboard / adbkeyboard-b64 |
| adbKeyboardInstalled | false | 设备装了 ADBKeyboard 时,auto 走 base64 |
| visionFallback | true | 是否允许视觉兜底 |
| visionCommand | 空 | 外部视觉命令(见第 5 节) |
| visionTimeoutMs | 20000 | 视觉命令超时 |
| screenshotDir | <dsh-home>/quick-adb/shots | 兜底截图目录 |
| maxShots | 50 | 截图保留张数,超出按时间清理 |
| allowShell | true | 是否允许 adb_shell(批量的 shell 步骤同受此限) |
| maxOutputChars | 8000 | adb_shell 返回上限 |
| timingEnabled | true | 是否落盘 JSONL |
| timingFile | <dsh-home>/quick-adb/timing.jsonl | 计时日志路径 |
| baselineStepMs / baselineAdbCalls | 0 | 优化前基线,用于报告算加速比 |
| includeScreenInAction | true | 动作结果是否附界面摘要 |
| logLevel | info | debug / info / warn / error |

8. 用计时日志证明「真的变快了」

每次操作写一条 JSONL(<dsh-home>/quick-adb/timing.jsonl): json {"ts":"2026-11-01T06:12:07.412Z","op":"tap","kind":"op","wallMs":812,"adbCalls":1,"source":"dumped","ok":true,"serial":"192.168.1.20:5555"}

会话内看:

adb_timing # 全部样本
adb_timing {"last": 50} # 最近 50 步
adb_timing {"includeInternal": true} # 连内部 dump/probe 一起看

严格的 A/B: bash

旧流程基线(同一台设备、同一批坐标);--vision-ms / --gen-ms 换成你自己日志里的实测值

node scripts/bench.mjs --real --serial 192.168.1.20:5555 --x 540 --y 1200 --steps 10 \
--vision-ms 2500 --gen-ms 1200

把基线写进配置,之后 adb_timing 的结论与 bench 完全一致

baselineStepMs: 4241

baselineAdbCalls: 2.00

判定标准:看 p95 而不是均值;往返/步 ≤ 1.2 才算合并生效;零成本命中率 > 60% 才算缓存有效;视觉兜底计数为 0 是健康信号。

9. 安全边界

- allowShell: false 同时约束 adb_shell 与 adb_batch 的 shell 步骤(v0.2 修复)。
- adb_app 的 package / activity 先做白名单校验(com.example.app 形态),非法输入直接拒绝且不产生任何 ADB 调用;命令里再做一层引号包裹。
- adb_input 的文本经单引号转义,不会注入到设备 shell。
- visionCommand 走 spawn(shell:true),配置即代码执行,只填可信命令;默认空即禁用。
- 截图与 dump 文本可能含敏感信息,注意落盘目录权限与模型上下文暴露范围。

10. 已知限制

1. 自绘界面拿不到控件树:WebView(未开无障碍)、Flutter、Unity/游戏、部分 DRM 页会 dump 出 1 个节点或空层级,自动落到视觉兜底(仍是慢路径)。
2. 中文输入:input text 多数设备只吃 ASCII;需装 ADBKeyboard 并设 inputMode: adbkeyboard-b64。含 % 的文本同样建议走 base64——input text 用 %s 表示空格,字面 %s 无法表达。
3. 同一 Activity 内的界面变化:focus 不变时 L2 只能靠「无动作 + 时间窗」保证不复用陈旧数据;任何动作后缓存立即作废,这是刻意选择。
4. --compressed 兼容性:老设备不支持时自动降级;单纯超时不会永久降级(v0.2 修复)。
5. 多设备:要求 profile 内只有一台在线设备,多台必须显式配 serial,否则直接报错并列出现有设备。
6. 密码框:uiautomator 通常不返回密码明文;但其他文本会进入模型上下文,涉密界面请自行控制。

11. 测试 bash
node scripts/selftest.mjs # 95 项(无 dsh 依赖);装进 dsh 后多跑 22 项工具层断言,共 117 项
node scripts/bench.mjs # 单步耗时对比(mock 或 --real)

覆盖:解析 / 定位 / L1 / L2 / 动作合成 / settle:none 失效 / 批处理 / verify:false 失效 / allowShell 全链路 / 包名注入 / 等待超时上界 / dump 降级链 / 视觉兜底(含 visionCommand 成功路径)/ 计时 / 工具层。

License: MIT
预览分享卡片长什么样 ↓BBZ-bob/dsh-quick-adb
分享 · DeepSeek Harness Hub
BBZ-bob/dsh-quick-adb

用控件树定位操作安卓手机,免截图识图提速

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部