微信小程序蓝牙开发避坑实录:从设备ID到特征值,一次讲透数据收发
2026/6/14 0:07:00 网站建设 项目流程

微信小程序蓝牙开发实战指南:从协议栈解析到数据收发优化

蓝牙技术在小程序中的应用越来越广泛,但开发过程中总会遇到各种"坑"。本文将带你深入理解蓝牙协议栈在小程序中的实现方式,并分享一些实战中积累的经验和技巧。

1. 蓝牙协议栈在小程序中的映射

蓝牙协议栈是蓝牙通信的基础架构,理解它对于开发稳定可靠的蓝牙功能至关重要。在小程序中,蓝牙协议栈主要体现为三个层级:设备层、服务层和特征值层。

每个蓝牙设备都有一个唯一的设备ID(deviceId),这是连接设备的起点。设备ID下包含多个服务UUID(serviceId),每个服务又包含多个特征值UUID(characteristicId)。特征值是实际进行数据交互的端点,具有不同的权限属性:

  • read:可读取数据
  • write:可写入数据
  • notify:可订阅通知
  • indicate:可订阅指示(类似notify但更可靠)

在实际开发中,我们最常使用的是具有write和notify权限的特征值,分别用于发送和接收数据。

2. 蓝牙连接全流程解析

2.1 初始化与授权

蓝牙开发的第一步是获取用户授权并初始化蓝牙适配器。这里有几个关键点需要注意:

// 检查蓝牙授权状态 wx.getSetting({ success(res) { if (!res.authSetting['scope.bluetooth']) { // 请求授权 wx.authorize({ scope: 'scope.bluetooth', success() { initBluetoothAdapter(); } }); } else { initBluetoothAdapter(); } } }); function initBluetoothAdapter() { wx.openBluetoothAdapter({ success(res) { startDiscovery(); }, fail(res) { // 常见失败原因:用户未开启蓝牙或定位 console.error('初始化失败', res); } }); }

提示:在Android设备上,蓝牙扫描需要同时开启定位权限。如果遇到扫描不到设备的情况,请检查定位权限是否已授予。

2.2 设备发现与连接

发现设备后,我们需要筛选目标设备并建立连接:

let targetDeviceId = null; wx.startBluetoothDevicesDiscovery({ success(res) { wx.onBluetoothDeviceFound((res) => { const devices = res.devices; devices.forEach(device => { if (device.name === '你的设备名称') { targetDeviceId = device.deviceId; connectDevice(targetDeviceId); } }); }); } }); function connectDevice(deviceId) { wx.createBLEConnection({ deviceId, success(res) { // 连接成功后立即停止扫描以节省电量 wx.stopBluetoothDevicesDiscovery(); discoverServices(deviceId); }, fail(res) { console.error('连接失败', res); } }); }

3. 服务与特征值发现

连接设备后,我们需要发现可用的服务和特征值。这是最容易出问题的环节之一。

3.1 服务发现

function discoverServices(deviceId) { wx.getBLEDeviceServices({ deviceId, success(res) { const services = res.services; // 通常主服务是第一个,但并非绝对 const primaryService = services.find(s => s.isPrimary) || services[0]; discoverCharacteristics(deviceId, primaryService.uuid); } }); }

3.2 特征值发现与筛选

特征值的筛选是关键步骤,我们需要找到具有write和notify权限的特征值:

function discoverCharacteristics(deviceId, serviceId) { wx.getBLEDeviceCharacteristics({ deviceId, serviceId, success(res) { const characteristics = res.characteristics; let writeChar = null; let notifyChar = null; characteristics.forEach(char => { if (char.properties.write) { writeChar = char.uuid; } if (char.properties.notify || char.properties.indicate) { notifyChar = char.uuid; } }); if (writeChar && notifyChar) { setupCommunication(deviceId, serviceId, writeChar, notifyChar); } else { console.error('未找到所需的特征值'); } } }); }

注意:不同设备的特征值UUID可能不同,建议查阅设备文档或使用蓝牙调试工具确认。

4. 数据收发优化

4.1 数据发送策略

小程序蓝牙发送数据有20字节的限制,对于大数据需要分包发送:

function sendData(deviceId, serviceId, characteristicId, data) { const buffer = new ArrayBuffer(data.length); const dataView = new Uint8Array(buffer); for (let i = 0; i < data.length; i++) { dataView[i] = data.charCodeAt(i); } let offset = 0; while (offset < buffer.byteLength) { const chunk = buffer.slice(offset, offset + 20); offset += 20; wx.writeBLECharacteristicValue({ deviceId, serviceId, characteristicId, value: chunk, success(res) { console.log('数据发送成功'); }, fail(res) { console.error('数据发送失败', res); } }); } }

4.2 数据接收处理

接收数据时需要处理ArrayBuffer格式:

function setupNotification(deviceId, serviceId, characteristicId) { wx.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId, state: true, success(res) { wx.onBLECharacteristicValueChange((res) => { const value = res.value; const hexString = ab2hex(value); // 处理接收到的数据 processReceivedData(hexString); }); } }); } function ab2hex(buffer) { const hexArr = Array.prototype.map.call( new Uint8Array(buffer), function(bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(''); }

5. 常见问题排查

5.1 连接不稳定问题

蓝牙连接可能会意外断开,建议实现自动重连机制:

let reconnectAttempts = 0; const maxReconnectAttempts = 3; wx.onBLEConnectionStateChange((res) => { if (!res.connected) { if (reconnectAttempts < maxReconnectAttempts) { reconnectAttempts++; setTimeout(() => { connectDevice(res.deviceId); }, 1000); } } else { reconnectAttempts = 0; } });

5.2 性能优化建议

  • 连接成功后立即停止扫描
  • 页面隐藏时断开连接和通知
  • 合理设置重连间隔和次数
Page({ onHide() { if (this._deviceId) { wx.closeBLEConnection({ deviceId: this._deviceId }); wx.stopBluetoothDevicesDiscovery(); } } });

在实际项目中,我发现蓝牙设备的响应时间差异很大。有些设备连接后需要几秒钟才能准备好通信,而有些则可以立即响应。针对这种情况,可以在连接成功后设置一个短暂的延迟再开始通信,或者在首次通信失败后加入重试逻辑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询