微信小程序蓝牙开发实战指南从协议栈解析到数据收发优化蓝牙技术在小程序中的应用越来越广泛但开发过程中总会遇到各种坑。本文将带你深入理解蓝牙协议栈在小程序中的实现方式并分享一些实战中积累的经验和技巧。1. 蓝牙协议栈在小程序中的映射蓝牙协议栈是蓝牙通信的基础架构理解它对于开发稳定可靠的蓝牙功能至关重要。在小程序中蓝牙协议栈主要体现为三个层级设备层、服务层和特征值层。每个蓝牙设备都有一个唯一的设备IDdeviceId这是连接设备的起点。设备ID下包含多个服务UUIDserviceId每个服务又包含多个特征值UUIDcharacteristicId。特征值是实际进行数据交互的端点具有不同的权限属性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(); } } });在实际项目中我发现蓝牙设备的响应时间差异很大。有些设备连接后需要几秒钟才能准备好通信而有些则可以立即响应。针对这种情况可以在连接成功后设置一个短暂的延迟再开始通信或者在首次通信失败后加入重试逻辑。
微信小程序蓝牙开发避坑实录:从设备ID到特征值,一次讲透数据收发
发布时间:2026/6/14 0:07:01
微信小程序蓝牙开发实战指南从协议栈解析到数据收发优化蓝牙技术在小程序中的应用越来越广泛但开发过程中总会遇到各种坑。本文将带你深入理解蓝牙协议栈在小程序中的实现方式并分享一些实战中积累的经验和技巧。1. 蓝牙协议栈在小程序中的映射蓝牙协议栈是蓝牙通信的基础架构理解它对于开发稳定可靠的蓝牙功能至关重要。在小程序中蓝牙协议栈主要体现为三个层级设备层、服务层和特征值层。每个蓝牙设备都有一个唯一的设备IDdeviceId这是连接设备的起点。设备ID下包含多个服务UUIDserviceId每个服务又包含多个特征值UUIDcharacteristicId。特征值是实际进行数据交互的端点具有不同的权限属性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(); } } });在实际项目中我发现蓝牙设备的响应时间差异很大。有些设备连接后需要几秒钟才能准备好通信而有些则可以立即响应。针对这种情况可以在连接成功后设置一个短暂的延迟再开始通信或者在首次通信失败后加入重试逻辑。