Web Serial API:navigator.serial 串口访问
发布于 更新于
一句话: Web Serial API 让页面通过 navigator.serial.requestPort() 请求用户选择一个
串口,然后通过返回的 SerialPort 的 readable/writable 流读写字节。MDN 将 Serial
接口标记为非 Baseline——“because it does not work in some of the most widely-used
browsers”(因为它在一些广泛使用的浏览器中无法工作)——并且只在安全上下文中暴露。
请求并复用端口
Section titled “请求并复用端口”const port = await navigator.serial.requestPort();await port.open({ baudRate: 9600 });根据 MDN,requestPort() “must be called via transient activation”(必须通过用户激活调用)
——应在点击事件等用户手势中触发,而不是在页面加载时自动调用。navigator.serial.getPorts()
会返回当前已连接、且该源已拥有访问权限的端口组成的数组,而不会再次弹出提示:
const ports = await navigator.serial.getPorts();访问也可能被 serial 权限策略(Permissions Policy)阻止;根据 MDN,被阻止的页面不会显示
设备选择器,用户也不会看到提示。
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Desktop) | 支持 | 89 | 高 | 来源 | — |
| Chrome (Android) | 支持 | 148 | 高 | 来源 | — |
| Edge (Desktop) | 支持 | 89 | 高 | 来源 | 1 |
| Firefox (Desktop) | 支持 | 151 | 高 | 来源 | — |
| Firefox (Android) | 不支持 | — | 高 | 来源 | 2 |
| Safari (macOS) | 不支持 | — | 高 | 来源 | 3 |
| Safari (iOS) | 不支持 | — | 高 | 来源 | 45 |
| Samsung Internet | 部分支持 | 30.0 | 高 | 来源 | 67 |
| WebView (Android) | 不支持 | — | 高 | 来源 | 8 |
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- browser-compat-data 未记录 Firefox for Android 的支持。
- browser-compat-data 未记录 Safari 的支持。
- browser-compat-data 未记录 iOS 版 Safari 的支持。
- 由 browser-compat-data 镜像自 Safari 的数据推导。
- 仅当串口由蓝牙 RFCOMM 串口仿真提供时才可用。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
- 实现跟踪:https://crbug.com/40740509。
根据上方的兼容性数据,桌面版 Chrome 和 Edge 自 89 版起支持该 API,桌面版 Firefox 则较晚 才支持,为 151 版起。Safari 在 macOS 和 iOS 上均不支持。在 Android 上,根据 MDN 的 browser-compat-data,Chrome 自 148 版起完整支持;138–146 版的串口“are only available if they are provided by Bluetooth RFCOMM serial port emulation”(仅在由蓝牙 RFCOMM 串口仿真提供时可用)。 Firefox for Android 不支持该 API。
const reader = port.readable.getReader();try { while (true) { const { value, done } = await reader.read(); if (done) break; console.log(value); }} finally { reader.releaseLock();}navigator.serial 还会派发 connect 与 disconnect 事件——从 SerialPort 冒泡而来
——因此页面可以在已授权设备被接入或移除时做出响应,而不必轮询 getPorts()。
如何在运行时检测
Section titled “如何在运行时检测”async function connectSerial() { if (!('serial' in navigator)) { // 此处不支持 Web Serial —— 回退到 WebUSB,或引导用户使用原生配套应用, // 而不是调用 navigator.serial。 return null; } const port = await navigator.serial.requestPort(); await port.open({ baudRate: 9600 }); return port;}-
requestPort()需要用户激活——应在点击事件处理函数中调用,而不是在页面加载时自动 调用,否则返回的 Promise 会被拒绝。 - 在调用任何方法之前先做特性检测
'serial' in navigator;MDN 将 Web Serial 标记为 非 Baseline,因此某些浏览器不支持是预期情况。 - 通过 HTTPS 提供页面——
Serial接口只在安全上下文中暴露。 - 在 Android 上,先确认 Chrome 版本再假设能访问 USB 连接的设备——根据 MDN 的 browser-compat-data,138–146 版仅覆盖蓝牙 RFCOMM 仿真,148 起为完整支持。
- 在加载时先调用
getPorts(),再回退到requestPort(),以便复用此前已授权的端口 而无需再次弹出提示。 - 页面也可能被
serial权限策略直接阻止弹出提示——应将这种失败模式与用户主动拒绝 区分开来处理。
- WebUSB API —— 关于未被操作系统驱动程序占用的 USB 设备的相关参考条目。
- WebHID API —— 关于 USB HID 类输入设备的 相关参考条目。