如何通过Web Bluetooth API获取Eddystone URL信标信息
问题背景
- 尝试通过Web Bluetooth API枚举Eddystone URL信标,最初参考设备信息示例代码,使用
0xfeaa作为蓝牙服务过滤条件,后续也逐一测试过Eddystone配置服务列出的所有UUID,均无法正常获取信标URL。 - 信标本身配置正常:通过Beacon Simulator应用扫描可正常发现目标信标,检测到其服务UUID为预期的
0000FEAA-...,应用侧显示的信标信息如下:
- 核心需求:仅通过Web端API实现信标URL获取,不依赖原生应用能力。
问题原因
常规示例代码的调用方式存在两个核心误区:
- 普通
navigator.bluetooth.requestDevice()接口仅能完成设备发现、GATT连接,无法直接获取BLE广播包中携带的服务数据,而Eddystone-URL的URL内容默认是直接封装在0xFEAA服务的广播帧中,不需要建立GATT连接就能读取。 - 测试中用到的Eddystone配置服务UUID,仅支持GATT配置的可连接Eddystone信标才会暴露,绝大多数纯广播模式的Eddystone URL信标是不可连接的,不会对外暴露配置相关的GATT特征,自然无法通过连接读取的方式拿到内容。
实现方案
使用Web Bluetooth的低功耗广播监听API直接解析广播帧中的服务数据即可,不需要和信标建立连接,具体实现步骤如下:
- 调用
navigator.bluetooth.requestLEScan()启动广播监听,过滤规则指定匹配Eddystone服务UUID0000feaa-0000-1000-8000-00805f9b34fb,开启服务数据接收权限。 - 监听
advertisementreceived事件,从事件返回的广播数据中提取0xFEAA服务对应的二进制数据。 - 按照Eddystone-URL的帧格式解析二进制内容,还原出完整URL。
可直接运行的参考代码:
// Eddystone URL 前缀映射表 const URL_SCHEMES = { 0: 'http://www.', 1: 'https://www.', 2: 'http://', 3: 'https://' }; // Eddystone URL 后缀编码映射表 const URL_EXPANSIONS = [ '.com/', '.org/', '.edu/', '.net/', '.info/', '.biz/', '.gov/', '.com', '.org', '.edu', '.net', '.info', '.biz', '.gov' ]; async function scanEddystoneBeacons() { try { // 申请广播扫描权限 const scan = await navigator.bluetooth.requestLEScan({ filters: [{ services: ['0000feaa-0000-1000-8000-00805f9b34fb'] }], keepRepeatedDevices: true }); // 监听广播事件 navigator.bluetooth.addEventListener('advertisementreceived', event => { const serviceData = event.serviceData.get('0000feaa-0000-1000-8000-00805f9b34fb'); if (!serviceData) return; const frameType = serviceData.getUint8(0); // 帧类型0x10对应Eddystone-URL if (frameType !== 0x10) return; // 跳过索引1的Tx功率字节 const schemePrefix = serviceData.getUint8(2); if (!URL_SCHEMES.hasOwnProperty(schemePrefix)) return; let url = URL_SCHEMES[schemePrefix]; // 逐字节解析URL内容 for (let i = 3; i < serviceData.byteLength; i++) { const charCode = serviceData.getUint8(i); if (charCode < URL_EXPANSIONS.length) { url += URL_EXPANSIONS[charCode]; } else { url += String.fromCharCode(charCode); } } console.log('发现Eddystone URL信标:', event.device.name, 'URL:', url); }); } catch (err) { console.error('扫描失败:', err); } } // 扫描必须由用户主动手势触发,比如绑定到按钮点击事件 document.getElementById('scanBtn').addEventListener('click', scanEddystoneBeacons);
注意事项
- 该API要求页面运行在HTTPS环境下,本地调试可使用localhost。
- Chrome 79及以上版本才支持
requestLEScan相关广播监听能力,其余浏览器兼容性需要单独验证。 - 扫描动作必须由用户主动手势触发,无法在页面加载后自动启动扫描。
- 如果是支持配置的可连接Eddystone信标,也可以在连接GATT后读取配置服务的URL特征值,但这种方案兼容性远低于直接解析广播帧的实现。
内容的提问来源于stack exchange,提问作者Alberto Sanchez Gonzalez
相关产品推荐
相关产品推荐

