这个文章是用来记录下技术原理。
前段时间总是被产品纠正截电视机的图,截了100多张,虽然现在有ai,但是也是要一张张的截图,人都截图截傻了还耽误时间,本来有app可以截图,但是产品手机又是ios手机,我就想着能不能做个小程序,经过我一个晚上的问ai做测试终于把他给做成了,小程序名字叫
“安卓5555工具箱”
以后截图的事产品也可以自己做了。
传统的 ADB 工作流通常是这样的:开发者在电脑端执行 adb shell ,系统中的 adb.exe (C/C++ 编写) 通过 USB 或局域网 TCP
连接到手机的 adbd 守护进程,从而进行设备认证与通信。
但在小程序中,没有任何底层的可执行文件。要在小程序这种纯 JavaScript 容器中运行原生 ADB
引擎,其核心技术实现可以拆解为以下三个关键层:
底层通信层:突破网络限制 (TCP Socket)
ADB 协议本质上是在网络层或 USB 传输层上收发二进制数据包。由于小程序环境无法直接调用系统的 USB
接口,但最新的微信小程序基础库开放了一个关键能力——原生
TCP Socket ( wx.createTCPSocket )。Android 手机开启“无线调试”或“网络 ADB”后,会在本地开启一个 TCP 端口(通常是
5555,这也是工具箱名字的由来)。我们只需要在小程序中调用原生的 Socket API 即可建立物理通道:
// 1. 创建小程序的 TCP 实例 const socket = wx.createTCPSocket(); // 2. 发起连接,直连 Android 手机的 5555 端口 socket.connect({ address: '192.168.1.100', // 手机的局域网 IP port: 5555 });这一步直接绕过了需要依托 PC 机做网络转发的限制,实现了移动设备到 Android 手机的端到端直连。
数据流封装层:拥抱 Web 规范 (Web Streams)
仅仅拥有 TCP 连接还不够,小程序的 Socket API 是基于事件回调机制的(如 onMessage
)。但现代化的前端协议处理库往往依赖于标准的流式读写接口。
为此,项目在底层设计了一个适配器,将非标准的 TCP 读写事件强行包装成了 Web 标准的 ReadableStream 和 WritableStream
,核心代码逻辑如下:
// 将 TCP 接收事件转换为 ReadableStream const readable = new ReadableStream<Uint8Array>({ start(controller) { socket.onMessage((res) => { // 当 TCP 收到数据,将其转为 Uint8Array 并压入流中 const chunk = new Uint8Array(res.message); controller.enqueue(chunk); }); } }); // 将 TCP 发送事件封装为 WritableStream const writable = new WritableStream<Uint8Array>({ write(chunk) { // 当协议库向流中写入数据时,通过 TCP 发送给目标手机 socket.write(chunk.buffer); } }); // 最终将它们暴露给上层: return { readable, writable }经过这一层的转换,小程序特有的网络 API 就具备了标准的流式 I/O 能力,为后续接入上层协议库铺平了道路。
协议解析层:引入 WebADB 核心引擎
通信打通了,数据流也标准化了,接下来面临的最难问题是:如何让 JavaScript 理解复杂的 ADB 加密握手协议和指令集?
“安卓5555工具箱”引入了开源界著名的 WebADB 协议库(NPM 包: @yume-chan/adb )。WebADB 原本是用纯 TypeScript
重写来服务于浏览器 WebUSB API 的,而工具箱将其进行了创造性的“嫁接”。
它跳过了 WebADB 默认的 WebUSB 传输层,直接将上面封装好的 TCP 数据流注入到 WebADB 的核心解析器中:
import { Adb, AdbDaemonTransport } from '@yume-chan/adb'; // 1. 拿到封装好的 TCP Stream (包含 readable 和 writable) const connection = await tcpDevice.connect(); // 2. 注入 WebADB 进行协议认证(处理复杂的 RSA 握手) const transport = await AdbDaemonTransport.authenticate({ serial: tcpDevice.serial, connection: connection, // 管理连接密钥,首次连接设备时屏幕会弹窗请求授权 credentialStore: new CustomLocalStorageCredentialManager('adb-credentials'), }); // 3. 认证成功,获得最终的纯 JS adb 实例 const adb = new Adb(transport); // ====================================== // 接下来即可通过 JS API 控制 Android 设备 // ====================================== // 示例:执行一条 shell 命令 const output = await adb.subprocess.noneProtocol.spawnWaitText('ls -l'); console.log("文件夹内容:", output); // 示例:获取手机型号 const model = await adb.getProp('ro.product.model'); console.log("手机型号:", model);前端展现层 (Taro + React)
底层通信与协议解析彻底走通后,最后一步就是 UI 交互的呈现。项目采用了 Taro 框架结合 React 语法,将 WebADB
解析出的底层数据(如系统属性、应用列表、命令行的输出流等)直接映射到组件状态上。当你点击界面上的“卸载应用”按钮时,本
质上就是触发了 adb 实例的一条指令。
总结
小程序之所以能够成立,核心在于串联了三项关键技术:
微信 TCP Socket(提供底层物理通道) ➡️ Web Streams API(提供标准化数据接口) ➡️ WebADB 协议库(提供 ADB
协议解析能力)。
它在没有原生 C++ 模块介入的情况下,利用纯 JavaScript 构建了硬核的系统级调试能力。这不仅是对 Web
技术边界的一次极佳探索,也向我们展示了优秀的底层开源协议库在不同容器环境中强大的复用潜力。