乐于分享
好东西不私藏

uniAPP 蓝牙API连接流程

uniAPP 蓝牙API连接流程

uniAPP 蓝牙连接流程
一、ble_utils.js 工具函数
// ==================== 工具函数 ====================// ArrayBuffer 转 16 进制数组(用于显示收到的数据)export function ab2hex(buffer) {  const hexArr = Array.prototype.map.call(    new Uint8Array(buffer),    function(bit) {      return ('00' + bit.toString(16)).slice(-2)    })  return hexArr}// 字符串转 ArrayBuffer(发送文本指令用)export function string2ArrayBuffer(str) {  let buffer = new ArrayBuffer(str.length)  let dataView = new Uint8Array(buffer)  for (let i = 0; i < str.length; i++) {    dataView[i] = str.charCodeAt(i)  }  return buffer}// 16进制字符串转 ArrayBuffer(发送 hex 指令用)export function hexString2ArrayBuffer(hexString) {  hexString = hexString.replace(/\s/g'')  let buffer = new ArrayBuffer(hexString.length / 2)  let dataView = new Uint8Array(buffer)  for (let i = 0; i < hexString.length; i += 2) {    dataView[i/2] = parseInt(hexString.substr(i, 2), 16)  }  return buffer}

二、BLE 蓝牙连接流程

// ==================== 蓝牙连接流程 ====================data(){  return {     deviceId'',      // 设备ID    serviceId'',      // 服务ID    writeCharId'',    // 写特征值ID    notifyCharId'',   // 通知特征值ID    connectedfalse    // 连接状态  }},methods:{  /**			 * 1. 初始化蓝牙适配器			 * 这是所有蓝牙操作的第一步,相当于打开手机的蓝牙功能开关。			 * 如果失败,通常是因为手机蓝牙未开启,或者应用未获得相关权限。			 */initBluetooth() {				uni.openBluetoothAdapter({success(res) => {console.log('初始化蓝牙成功', res)this.startDiscover()					},fail(err) => {console.error('初始化蓝牙失败', err)// 常见原因:手机未开启蓝牙、位置权限未开启						uni.showToast({title'请开启手机蓝牙',icon'none'						})					}				})			},/**			 * 2. 先监听设备发现,再开始扫描			 * 重要:很多开发者在这里顺序搞反了!			 * 必须先注册监听函数,再开始扫描。否则在监听函数注册之前扫描到的设备,			 * 你的程序是收不到的,就会导致“明明设备在那里,就是扫不到”的诡异问题。			 */startDiscover() {// 先注册监听(重要!必须先监听后扫描)				uni.onBluetoothDeviceFound((res) => {const devices = res.devicesconsole.log('发现设备', devices)// 这里可以根据设备名筛选目标设备					devices.forEach(device => {if (device.name && device.name.includes('目标设备名')) {console.log('找到目标设备', device)this.stopScanAndConnect(device.deviceId)						}					})				})// 开始扫描				uni.startBluetoothDevicesDiscovery({allowDuplicatesKeyfalse// 是否允许重复上报success(res) => {console.log('开始扫描设备', res)// 设置扫描超时(比如10秒)setTimeout(() => {this.stopScan()						}, 10000)					},fail(err) => {console.error('启动扫描失败', err)					}				})			},/**			 * 3. 停止扫描			 * 找到目标设备后应立即停止扫描,既省电又避免干扰后续的连接操作。			 */stopScan() {				uni.stopBluetoothDevicesDiscovery({success(res) => {console.log('停止扫描', res)					}				})			},/**			 * 4. 找到设备后停止扫描并连接			 */stopScanAndConnect(deviceId) {this.stopScan()this.connectDevice(deviceId)			},/**			 * 5. 连接蓝牙设备			 * 使用扫描到的 deviceId 建立连接。这个 deviceId 是设备的唯一标识,			 * 后续所有操作都要用到它,一定要保存好。			 */connectDevice(deviceId) {				uni.createBLEConnection({deviceId: deviceId,success(res) => {console.log('连接设备成功', res)this.setData({							deviceId,connectedtrue						})// 6. 设置MTU(Android必做!)this.setMTU(deviceId)					},fail(err) => {console.error('连接设备失败', err)					}				})			},/**			 * 6. 设置MTU(关键步骤)			 * MTU 是“最大传输单元”,决定了你一次能发送多少字节的数据。			 * Android 设备默认 MTU 只有 20 字节,如果不设置大一点,发稍长的指令就会被截断。			 * iOS 会自动协商,但 Android 必须手动设置。			 * 注意:setBLEMTU 在部分平台可能不支持,需要做兼容处理。			 */setMTU(deviceId) {// 注意:setBLEMTU 在微信小程序中可能不支持,UniApp 需根据平台判断// #ifdef APP-PLUS				uni.setBLEMTU({deviceId: deviceId,mtu128// 通常设为128,部分设备支持512success(res) => {console.log('设置MTU成功', res)this.getServices(deviceId)					},fail(err) => {console.log('设置MTU失败,继续获取服务', err)this.getServices(deviceId)					}				})// #endif// #ifdef H5 || MP - WEIXINthis.getServices(deviceId)// #endif			},/**			 * 7. 获取设备服务			 * 蓝牙设备可以包含多个服务(Service),每个服务相当于一个功能模块。			 * 比如有的服务负责电量显示,有的负责数据传输。			 * 我们需要找到负责数据通信的那个服务,通常 UUID 以 FFF0、FFE0 等开头。			 */getServices(deviceId) {				uni.getBLEDeviceServices({deviceId: deviceId,success(res) => {console.log('获取服务列表', res.services)// 找到需要的服务(通常根据UUID筛选)const services = res.services// 示例:假设目标服务的UUID以 'FFF0' 开头const targetService = services.find(s =>							s.uuid.toUpperCase().includes('FFF0')						)if (targetService) {this.setData({serviceId: targetService.uuid							})this.getCharacteristics(deviceId, targetService.uuid)else {console.error('未找到目标服务')						}					},fail(err) => {console.error('获取服务失败', err)					}				})			},/**			 * 8. 获取特征值			 * 每个服务下面包含多个特征值(Characteristic),			 * 特征值才是真正读写数据的地方。我们需要找到:			 * - 写特征值(write):用来给设备发指令			 * - 通知特征值(notify):用来接收设备主动发来的数据			 */getCharacteristics(deviceId, serviceId) {				uni.getBLEDeviceCharacteristics({deviceId: deviceId,serviceId: serviceId,success(res) => {console.log('获取特征值列表', res.characteristics)const chars = res.characteristics// 找到写特征值(properties.write 为 true)const writeChar = chars.find(c => c.properties.write)// 找到通知特征值(properties.notify 为 true)const notifyChar = chars.find(c => c.properties.notify)if (writeChar) {this.setData({writeCharId: writeChar.uuid							})						}if (notifyChar) {this.setData({notifyCharId: notifyChar.uuid							})// 9. 先监听数据(重要!)this.listenData()// 10. 再开启notifythis.enableNotify(deviceId, serviceId, notifyChar.uuid)						}					},fail(err) => {console.error('获取特征值失败', err)					}				})			},/**			 * 9. 监听设备返回的数据			 * 这个监听器要放在开启 notify 之前注册,否则设备发来的第一包数据可能会漏掉。			 * 收到的数据是 ArrayBuffer 格式,需要用 ab2hex 转成可读的十六进制字符串。			 */listenData() {				uni.onBLECharacteristicValueChange((res) => {// 收到的数据是 ArrayBuffer 格式const hexData = ab2hex(res.value)console.log('收到数据', hexData)// 也可以转成字符串(如果是文本数据)// const strData = String.fromCharCode.apply(null, new Uint8Array(res.value))// 更新到页面显示this.setData({receivedData: hexData.join(' ')					})				})			},/**			 * 10. 开启notify服务			 * 只有开启了 notify,设备才会主动把数据推送给手机。			 * 这就像是你跟设备说:“好了,现在有什么消息随时告诉我吧。”			 */enableNotify(deviceId, serviceId, characteristicId) {				uni.notifyBLECharacteristicValueChange({statetrue,deviceId: deviceId,serviceId: serviceId,characteristicId: characteristicId,success(res) => {console.log('开启notify成功', res)						uni.showToast({title'蓝牙连接成功',icon'success'						})					},fail(err) => {console.error('开启notify失败', err)					}				})			},/**			 * 11. 发送指令			 * 支持两种格式:			 * - 文本格式:直接发 "AT+CMD" 这样的字符串			 * - 十六进制格式:发 "A1 B2 C3" 这样的 hex 数据@param {stringcommand - 指令内容(文本或hex字符串)@param {stringtype - 指令类型 'text' 或 'hex'			 */sendCommand(command, type = 'text') {if (!this.data.connected) {					uni.showToast({title'蓝牙未连接',icon'none'					})return				}// 转换数据格式let bufferif (type === 'hex') {					buffer = hexString2ArrayBuffer(command)else {					buffer = string2ArrayBuffer(command)				}				uni.writeBLECharacteristicValue({deviceIdthis.data.deviceId,serviceIdthis.data.serviceId,characteristicIdthis.data.writeCharId,value: buffer,success(res) => {console.log('指令发送成功', command)// 注意:设备的回复数据会触发 onBLECharacteristicValueChange// 不要在这里等待回复,回复会通过步骤9的监听器收到					},fail(err) => {console.error('指令发送失败', err)					}				})			},/**			 * 12. 断开连接(退出页面时必须调用)			 * 很多新手开发者忘了这一步,结果下次打开小程序发现蓝牙连不上了,			 * 或者手机蓝牙被占用导致其他设备连不上。			 * 一定要在页面卸载时释放资源!			 */disconnectBluetooth() {if (this.data.deviceId) {// 关闭连接					uni.closeBLEConnection({deviceIdthis.data.deviceId,success(res) => {console.log('断开连接成功', res)						}					})				}// 关闭蓝牙适配器				uni.closeBluetoothAdapter({success(res) => {console.log('关闭蓝牙适配器', res)this.setData({connectedfalse						})					}				})			},			} ,
本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » uniAPP 蓝牙API连接流程

猜你喜欢

  • 暂无文章