You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Electron中蓝牙DOMException错误?

问题解决方案:Electron蓝牙自定义选择器连接报错"User cancelled"

问题原因

navigator.bluetooth.requestDevice() 是Web Bluetooth API中用于唤起系统原生蓝牙选择器的方法,即使你通过filters指定了设备名称或ID,系统依然会弹出选择器要求用户确认。如果用户没有操作系统选择器(毕竟你已经用了自定义选择器),方法会超时抛出"User cancelled the requestDevice() chooser"错误。

正确实现方案

既然已经实现了自定义设备选择器,无需再调用requestDevice(),直接使用扫描时获取的BluetoothDevice对象连接即可。

1. 扫描设备时缓存完整的BluetoothDevice对象

替换你原来获取deviceList的逻辑,扫描时直接缓存设备对象,而非仅存储名称和ID:

// 初始化缓存数组,存储扫描到的蓝牙设备
let cachedBluetoothDevices = [];

// 启动蓝牙扫描
async function startBluetoothScan() {
  try {
    // 开启BLE扫描,acceptAllDevices设为true可扫描所有设备,也可指定services过滤
    await navigator.bluetooth.requestLEScan({
      acceptAllDevices: true,
    });

    // 监听设备广播事件,收集设备
    navigator.bluetooth.addEventListener('advertisementreceived', (event) => {
      const device = event.device;
      // 避免重复添加同一设备
      if (!cachedBluetoothDevices.find(item => item.id === device.id)) {
        cachedBluetoothDevices.push(device);
        // 更新自定义设备选择器列表,传入device对象
        updateCustomDeviceSelector(cachedBluetoothDevices);
      }
    });
  } catch (error) {
    console.error('扫描启动失败:', error);
  }
}

// 停止扫描(可选,比如用户关闭选择器时调用)
async function stopBluetoothScan() {
  await navigator.bluetooth.stopLEScan();
}

2. 用户点击自定义列表时直接连接设备

当用户在自定义选择器中点击设备时,直接用缓存的BluetoothDevice对象发起GATT连接:

// 自定义选择器的点击事件处理函数
async function handleDeviceSelect(selectedDevice) {
  try {
    // 检查设备是否已连接
    if (!selectedDevice.gatt.connected) {
      const gattServer = await selectedDevice.gatt.connect();
      console.log('设备连接成功:', selectedDevice.name);
      // 后续可执行获取服务、特征等操作
    } else {
      console.log('设备已处于连接状态');
    }
  } catch (error) {
    console.error('连接失败:', error);
  }
}

3. 仅存储设备ID的兼容方案

如果之前只存储了设备ID,可通过getDevices()获取已发现/配对的设备列表,再匹配ID连接:

async function connectDeviceById(deviceId) {
  try {
    // 获取浏览器已缓存的蓝牙设备
    const savedDevices = await navigator.bluetooth.getDevices();
    const targetDevice = savedDevices.find(device => device.id === deviceId);
    
    if (!targetDevice) {
      console.error('未找到目标设备,请重新扫描');
      return;
    }

    const gattServer = await targetDevice.gatt.connect();
    console.log('设备连接成功');
  } catch (error) {
    console.error('连接失败:', error);
  }
}

Electron额外注意事项

  • 权限配置:在macOS上,需在Electron的info.plist中添加蓝牙权限描述:
    <key>NSBluetoothAlwaysUsageDescription</key>
    <string>需要蓝牙权限连接设备</string>
    <key>NSBluetoothPeripheralUsageDescription</key>
    <string>需要蓝牙权限扫描周边设备</string>
    
    打包时确保这些权限被正确包含到应用包中。
  • 用户手势触发:所有蓝牙相关操作(扫描、连接)必须在用户手势(如click、tap事件回调)中触发,不能在页面加载或非用户交互逻辑中自动执行,否则会被系统拦截。
  • Electron版本:使用最新稳定版Electron,确保对Web Bluetooth API的支持完整。

内容的提问来源于stack exchange,提问作者Nyameaama Gambrah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 08:07:41