跳转到内容

WebUSB API:从网页连接非标准 USB 设备

发布于

一句话: WebUSB 让网页可以请求访问操作系统标准设备类(键盘、鼠标等)之外的 USB 设备——这些设备原本需要原生驱动或原生应用——方式是向用户展示一个权限提示,与特定设备 配对,无需下载任何驱动。它是一份 WICG 规范,既不是 W3C 标准,也不在 W3C 标准化轨道 上。

WebUSB 由 Web 平台孵化社区组(WICG)以社区组草案报告的形式发布;规范声明它“既不是 W3C 标准,也不在 W3C 标准化轨道上”。MDN 将该 API 标记为实验性且非 Baseline, “因为它在部分最广泛使用的浏览器中不可用”。

许多 USB 设备属于有操作系统驱动支持的标准化设备类,也可以通过 WebHID API 从网页访 问。而那些不属于标准类的设备,历来需要原生代码才能访问,这“使得这些设备无法被网页使 用”。WebUSB 让网页可以直接访问这些非标准化的设备服务。

WebUSB 仅在安全上下文中可用。调用 requestDevice() 时,调用脚本必须处于瞬态激 活状态(即近期发生过用户手势);若在没有用户手势的情况下调用,返回的 Promise 会以 SecurityError 被拒绝。

navigator.usb
.requestDevice({ filters: [{ vendorId: 0x2341 }] })
.then((device) => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"
})
.catch((error) => {
console.error(error);
});

requestDevice() 会对候选设备进行过滤(例如按 vendorId),根据规范,“UA 可能在 调用此函数时显示权限提示”。设备一旦获得授权后,navigator.usb.getDevices() 便可返 回此前已获授权的设备,而不会再次弹出提示:

navigator.usb.getDevices().then((devices) => {
devices.forEach((device) => {
console.log(device.productName);
});
});

UA “也可能在设备连接处于活动状态时显示一个指示器”。

WebUSB 的安全模型依赖于 requestDevice() 的权限提示,并结合权限策略 (Permissions Policy)集成,而非采用设备端的允许列表(规范中说明,曾考虑过类似 CORS 的方案但未被采纳)。此外,规范定义的 USB 屏蔽列表(Blocklist) 会限制对特定 设备的访问,识别依据是 vendorId、productId 与 bcdDevice。另外,受保护的接口类 无论是否在屏蔽列表中,都会被单独限制访问 WebUSB。

同一时刻只能有一个执行上下文声明(claim)某个 USB 接口——若多个执行上下文尝试声明 同一接口,claimInterface() 会失败。

USBDevice 提供已配对设备的元数据以及用于控制它的方法。设备被组织为 USBConfiguration → USBInterface → USBAlternateInterface → USBEndpoint 的层 级结构,每一层都提供该层级的信息。传输结果由 USBInTransferResult/ USBOutTransferResult(以及用于流式端点的等时传输变体)表示。

设备可以通过 WebUSB 平台能力描述符(Platform Capability Descriptor)的 iLandingPage 字段声明一个着陆页——“设备制造商希望用户访问以控制其设备的着陆页”。 UA 的角色仅是建议性的:它“可以(MAY)在设备连接时建议用户导航到该 URL”。浏览器通过 一个规范定义的 GET_URL 设备请求获取该地址,该请求返回一个 URL 描述符(包含协议前 缀与 UTF-8 编码的 URL 字符串)。

MDN 指出该特性在 Web Worker 中可用(WorkerNavigator.usb),此外主线程上还有 Navigator.usb。

  • 在调用任何 WebUSB 方法之前先进行特性检测:navigator.usb。
  • 通过 HTTPS 提供页面——WebUSB 仅在安全上下文中可用。
  • 仅在具有瞬态激活(用户手势)的脚本中调用 requestDevice();否则调用会以 SecurityError 被拒绝。
  • 使用 filters(例如 vendorId)将选择器范围限定到目标设备。
  • 在后续访问中调用 getDevices() 以复用此前已获授权的设备,而无需再次弹出提 示。
  • 上线前检查当前浏览器兼容性——MDN 将 WebUSB 标记为实验性且非 Baseline。
  • 如果你的设备声明了 iLandingPage,请记住浏览器的导航建议是可选的(MAY),并 非保证行为。