在开放网页上,点击一下就能让页面通过 navigator.bluetooth 申请附近的低功耗蓝牙(BLE)设备、连上它的 GATT 服务、读写特征值。但在 WebView 里,这个入口点根本不存在。Android WebView 根本不暴露 navigator.bluetooth——该属性直接是 undefined;MDN 的浏览器兼容数据把 WebView(Android)标记为"不支持"。iOS 的情况更隐蔽:Safari 和 WKWebView 都没有实现 Web Bluetooth,而 iOS 强制所有浏览器使用 WebKit 内核,于是 Chrome、Edge 在 iOS 上也继承同一道缺口。WebKit 对该规范投了"反对"立场,因此也没有任何在途实现可以等待。

对一个 WebView 页面来说,结论是跨引擎统一的:在桌面网页上能跑的代码,在这里要么抛错、要么静默无反应,页面内部没有任何回退手段。

就算存在,它也脆弱

值得强调的是,即便在支持 Web Bluetooth 的浏览器上,这个能力也很脆弱。Chrome 要求安全上下文(HTTPS)、一次瞬时用户激活(调用必须来自点击,而非定时器或 fetch 回调),并且维护一份内置黑名单,在选择器弹出前就隐藏掉部分厂商与产品 ID——其中就包括一些 FIDO 与 HID 类别。依赖它的页面,本来就已经距离"某个权限弹窗 + 某个开关"一步之遥就会崩。而在 WebView 里,连可以回退的浏览器都不存在,能力直接归零。

硬件配对失效后,什么会坏

  • 硬件安全密钥无法配对。 让用户在 BLE FIDO 认证器上确认提现的券商或交易所,无法从 WebView 页面完成这一步——认证器对页面完全不可见。
  • 硬件钱包保持断开。 需要配对硬件钱包来核验地址或签名的加密资产 / OTC 柜台,从内嵌网页内容没有任何通路。
  • 外设终端失灵。 商户小程序依赖的 BLE 小票打印机、扫码枪、POS 外设都无法触达。
  • 静默而非报错。 因为 API 是 undefined(或 iOS 上永不弹窗),失败是一种安静的"无反应"——用户拿不到任何可操作的错误提示,只有一个点了没反应的按钮。

runtime 解法

宿主自有 runtime 桥接蓝牙层。页面只调用一个统一 API——runtime.connectBle({ filters, onData })——宿主通过平台原生蓝牙栈解析它:Android 走 BluetoothGatt(基于 BluetoothAdapter),iOS 走 CoreBluetooth(CBCentralManager、CBPeripheral)。配对、服务发现、特征值读写都由原生一致地处理。一次集成,覆盖所有引擎,终点是一台真实硬件。

维度WebView宿主自有 runtime
navigator.bluetoothAndroid WebView 为 undefined;iOS WKWebView 缺失原生 BLE(CoreBluetooth / Android Bluetooth)
安全上下文 + 用户手势即便支持也强制要求宿主触发,无脆弱的激活令牌
设备类别Chrome 黑名单隐藏部分 FIDO/HID对已配对外设的完整 GATT 访问
硬件钱包 / 安全密钥无法配对原生配对 + 签名回传
小票打印机 / 扫码枪无法连接原生连接,可靠
一致性因引擎而异,大多缺失统一

原生 App 能在每台设备上配对 BLE 安全密钥;裸 WebView 在几乎任何设备上都不行。runtime 给页面一个 connect 调用——终点是一台真实的外设。

参考来源