通用技术 基于 WebUSB 与 CDP:在浏览器端实现 Android 设备通信与无证书抓包实践

Katrina · 2026年09月08日 · 109 次阅读

基于 WebUSB 与 CDP:在浏览器端实现 Android 设备通信与无证书抓包实践

在移动端 Android 调试与测试过程中,Scrcpy 等传统桌面工具通常依赖宿主机安装的 ADB Server(通过本地 5037 端口与设备通信)。虽然性能极高,但在日常跨团队协作或自动化测试交付时,往往面临本地环境依赖繁琐、多版本 ADB 端口冲突以及移动端 HTTPS 抓包配置复杂(如 Android 7+ 默认不信任用户根证书)等现实问题。

本文结合我们在开源浏览器扩展 TabQA 中的工程实践,探讨如何借助现代浏览器的 WebUSB APIChrome DevTools Protocol (CDP),在不依赖本地 ADB 服务与客户端的前提下,直接在浏览器端实现真机通信、投屏交互与免安装 CA 证书的网络抓包。


1. 底层通信:基于 WebUSB 的 ADB 协议握手

现代 Chromium 内核提供了 WebUSB API,允许在受信任的前端上下文(如用户主动授权后)中直接与物理 USB 设备进行底层的 Bulk 数据传输。

1.1 设备筛选与接口声明

在 Android 官方规范中,ADB 调试接口具有固定的类定义:

  • bInterfaceClass: 0xff (Vendor Specific)
  • bInterfaceSubClass: 0x42 (ADB)
  • bInterfaceProtocol: 0x01

在浏览器中,首先通过过滤条件唤起设备选择器:

// 1. 过滤并请求匹配 ADB 接口定义的 Android 设备
const device = await navigator.usb.requestDevice({
  filters: [{
    classCode: 0xff,
    subclassCode: 0x42,
    protocolCode: 0x01
  }]
});

// 2. 打开设备并独占 ADB 接口
await device.open();
await device.selectConfiguration(1);
const adbInterface = device.configuration.interfaces.find(iface =>
  iface.alternates.some(alt => alt.interfaceClass === 0xff && alt.interfaceSubclass === 0x42)
);
await device.claimInterface(adbInterface.interfaceNumber);

1.2 ADB 协议包封装与 RSA 鉴权

与桌面 ADB 二进制类似,浏览器与设备建立通信时,需要实现完整的 ADB 报文头结构:

// ADB 报文结构包含 24 字节头:command, arg0, arg1, data_length, data_checksum, magic
function createAdbPacket(command, arg0, arg1, payload = new Uint8Array(0)) {
  const header = new ArrayBuffer(24);
  const view = new DataView(header);

  view.setUint32(0, command, true);              // A_CNXN, A_OPEN, A_WRTE 等
  view.setUint32(4, arg0, true);
  view.setUint32(8, arg1, true);
  view.setUint32(12, payload.byteLength, true);  // 数据载荷长度
  view.setUint32(16, calculateChecksum(payload), true);
  view.setUint32(20, command ^ 0xffffffff, true);// magic 校验

  return concatBuffers(header, payload.buffer);
}

首次连接时,手机会返回 A_AUTH 要求授权。前端直接在内存中生成 2048 位 RSA 密钥对,将公钥转换为 Android ADB 兼容格式(Base64 + Token) 发送给手机,用户在真机点击 “允许 USB 调试” 后即可完成连接。整个链路不启动本地系统进程,彻底杜绝了多开发环境的端口抢占问题


2. 移动端网络抓包:基于 CDP 绕过根证书限制

在测试内嵌 H5 或混合开发(Hybrid)应用时,传统方案(如 Charles / Fiddler)需要修改系统 Wi-Fi 代理并安装 CA 根证书。但从 Android 7.0 (API 24) 开始,系统安全机制默认禁止信任用户安装的根证书。

2.1 端口映射与 DevTools 连接

Android 端运行的 Chrome 或开启了调试开关的 WebView(WebView.setWebContentsDebuggingEnabled(true)),底层都会开放一个 Unix domain socket(例如 @webview_devtools_remote_<pid>)。

通过 WebUSB 通道向设备发送端口转发指令后,浏览器端即可与目标 WebView 建立双向 WebSocket 连接。

2.2 注入网络监听指令

通过直接向 WebSocket 发送 Chrome 调试协议(CDP)指令,即可在运行时捕获底层网络事件,无需篡改任何 HTTP 证书:

// 向目标 WebView 的 DevTools 端口发送启用网络监听指令
function enableNetworkInspection(ws) {
  const message = {
    id: 1,
    method: 'Network.enable',
    params: {
      maxPostDataSize: 65536 // 捕获最大请求体
    }
  };
  ws.send(JSON.stringify(message));
}

// 监听网络响应与错误
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.method === 'Network.responseReceived') {
    const { requestId, response } = data.params;
    console.log(`[HTTP ${response.status}] ${response.url}`);

    // 获取响应体
    ws.send(JSON.stringify({
      id: generateId(),
      method: 'Network.getResponseBody',
      params: { requestId }
    }));
  }
};

该方案直接从渲染引擎内部获取网络事件,因此无论是 HTTPS 流量、证书固定(SSL Pinning)还是特定内网接口,都能完整提取请求体、响应头与耗时指标


3. 证据链对齐:环形缓冲区(Ring Buffer)在回捞中的应用

移动端偶发性 Crash 和 ANR 的一大痛点在于 “事后无法及时抓取现场”。如果全程进行全量录像和日志落盘,长时间测试会迅速耗尽系统内存。

在架构设计上,可以引入基于内存的环形缓冲区(Ring Buffer)机制:

class RingBuffer {
  constructor(capacity = 180) { // 维持最近 180 个切片(例如 3 分钟)
    this.buffer = new Array(capacity);
    this.capacity = capacity;
    this.head = 0;
    this.size = 0;
  }

  push(item) {
    this.buffer[this.head] = item;
    this.head = (this.head + 1) % this.capacity;
    if (this.size < this.capacity) this.size++;
  }

  // 提取按时序对齐的连续快照
  dump() {
    const result = [];
    let idx = this.size < this.capacity ? 0 : this.head;
    for (let i = 0; i < this.size; i++) {
      result.push(this.buffer[(idx + i) % this.capacity]);
    }
    return result;
  }
}
  • 视频流处理:通过 WebCodecs / MediaRecorder 将投屏流按 1 秒为粒度切分推入 Ring Buffer;
  • Logcat 流过滤:后台异步流式读取 adb logcat -v threadtime,正则匹配目标应用包名与 FATAL EXCEPTION / ANR 关键字;
  • 对齐触发:一旦捕获到崩溃信号或用户手动触发采集,系统瞬时将内存 Buffer 导出,生成时间戳完全锁定的短视频与异常上下文日志切片。

4. 架构对比与权衡思考

技术维度 传统桌面工具(如 QtScrcpy) 浏览器扩展架构(如 TabQA)
底层实现 C/C++ 宿主进程 + ADB Server (TCP 5037) JavaScript + 原生 WebUSB API (USB Bulk)
环境依赖 依赖宿主机环境与 ADB 安装 零外部依赖,Chrome/Edge 开箱即用
渲染开销 原生 GPU 渲染,支持 60~120fps 高刷 Canvas/WebCodecs 渲染,兼顾常规业务交互
网络层探针 无内置网络探针,需借助系统代理 基于 CDP 协议直接监听,免装 CA 根证书
适用定位 极致流畅度需求(手游映射、长视频) 敏捷功能测试、缺陷证据链对齐与交付

5. 总结

将 Android 设备的连接、投屏与调试搬进浏览器侧边栏,本质上是利用了现代 Web 技术(WebUSB、WebCodecs、CDP)打破传统桌面工具与 Web 用例管理系统之间的窗口壁垒。

以上方案的完整实现已开源在项目 TabQA 中(可在 GitHub 搜索 openutx/TabQA 查阅完整源码与实现细节)。对于正在探索移动端效能工具研发、轻量化测试工作流的开发者而言,基于浏览器底层标准构建无驱动、一体化的测试套件,提供了一种兼具便携度与扩展性的工程落地新视角。

暫無回覆。
需要 登录 後方可回應,如果你還沒有帳號按這裡 注册