当前位置: 首页 > news >正文

uniapp 实现 ble蓝牙同时连接多台蓝牙设备,支持app、苹果(ios)和安卓手机,以及ios连接蓝牙后的一些坑

首先对 uniapp BLE蓝牙API进行封装

这里我封装了一个类:bluetoothService.js

代码:

import { throttle } from 'lodash'
export default class Bluetooth {constructor() {this.device = {};this.connected = false;// 使用箭头函数绑定类实例的上下文,并在构造函数中初始化// 你可以在这里传入蓝牙信息进行保存this.throttledUpdate = throttle(async (params) => {// 多设备上传数据建议做下节流处理console.log(params)}}, 700); // 节流: 规定时间内最多更新一次}init() {return new Promise((resolve, reject) => {uni.openBluetoothAdapter({success: (res) => {resolve(res)console.log("初始化成功", res)},fail: (err) => {console.log("初始化失败:", err)reject(err)},})})}closeBluetoothAdapter() {return new Promise((resolve, reject) => {uni.closeBluetoothAdapter({success: (res) =>  {resolve(res)},fail: (err) => {reject(err)}})})}searchDevices() {return new Promise((resolve, reject) => {uni.startBluetoothDevicesDiscovery({success: () => {console.log('开始搜索蓝牙设备');uni.onBluetoothDeviceFound((res) => {if (res.devices[0]?.name.startsWith("SW")) { // 过滤条件只获取含SW开头名称的蓝牙,大家按需修改修改console.log(res)// 这里是设备,这里扫描到的设备,可以保存起来resolve(res.devices)}});},fail: (err) => {console.error('搜索蓝牙设备失败:', err);reject(err)},});})}stopSearchDevices() {return new Promise((resolve, reject) => {uni.stopBluetoothDevicesDiscovery({success: () => {console.log('停止搜索蓝牙设备');resolve('停止搜索蓝牙设备')},fail: (err) => {console.error('停止搜索蓝牙设备失败:', err);reject(err);}});})}connect(deviceId) {return new Promise((resolve, reject) => {uni.createBLEConnection({deviceId: deviceId,success: (res) => {this.device.deviceId = deviceId;this.connected = true;resolve(res)},fail: (err) => {console.error('蓝牙连接失败:', deviceId, err); // 处理连接失败reject(err)},complete: () => {// uni.hideLoading();this.stopSearchDevices()}});});}// 断开连接disconnect() {return new Promise((resolve, reject) => {if (this.connected) {uni.closeBLEConnection({deviceId: this.device.deviceId,success: () => {this.connected = false;this.device = {};resolve();},fail: (err) => {reject(err);}});} else {resolve();}});}// 监听蓝牙连接状态listenBLEStateChange() {return new Promise((resolve, reject) => {uni.onBLEConnectionStateChange((res) => {console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`);if (res.connected) {this.connected = true;resolve(res);} else {this.connected = false;reject(res)}});});}// 获取服务UUIDgetServices() {return new Promise((resolve, reject) => {uni.getBLEDeviceServices({deviceId: this.device.deviceId,success: (res) => {console.log('获取服务成功:', res.services);// 这里你们需要根据你们的设备修改// this.device.serviceId = res.services[2]?.uuid;this.device.serviceId = uni.getSystemInfoSync().platform === "android" ? res.services[2]?.uuid : res.services[1]?.uuid;resolve(res)},fail: (err) => {console.error('获取服务失败:', err);reject(err)},});})}getCharacteristics() {return new Promise((resolve, reject) => {uni.getBLEDeviceCharacteristics({deviceId: this.device.deviceId,serviceId: this.device.serviceId,success: (res) => {console.log('获取特征值成功:', res);// 找到对应的特征值UUIDres.characteristics.forEach((item) => {if (item.properties.notify === true) {this.device.characteristicsNotify = item.uuid // 监听特征}if (item.properties.write === true) {this.device.characteristicsWrite = item.uuid // 写入特征}})resolve(this.device)},fail: (err) => {console.error('获取特征值失败:', err);reject(err)// 处理获取特征值失败},});})}// 开启监听startNotify() {return new Promise((resolve, reject) => {uni.notifyBLECharacteristicValueChange({state: true,deviceId: this.device.deviceId,serviceId: this.device.serviceId,characteristicId: this.device.characteristicsNotify,success: () => {this.listenBLEStateChange(); // 监听蓝牙状态resolve(this.device);},fail: (err) => {console.error('开启notify失败:', err);},});})}// 接收数据receiveData() {return new Promise((resolve, reject) => {uni.onBLECharacteristicValueChange((res) => {console.log("蓝牙上传的数据:", this.ab2hex(res.value))resolve(this.ab2hex(res.value));});});}// 发送数据sendData(data) {return new Promise((resolve, reject) => {if (this.connected) {uni.writeBLECharacteristicValue({deviceId: this.device.deviceId,serviceId: this.device.serviceId,characteristicId: this.device.characteristicsWrite,value: data,success: () => {resolve(this.device);},fail: (err) => {console.log("蓝牙指令写入失败:", err)reject(err);}});} else {reject('蓝牙未连接');}});}// 监听信号listenRSSI(deviceId, receiveData) {return new Promise((resolve, reject) => {uni.getBLEDeviceRSSI({deviceId: deviceId,success: (res) => {resolve(res.RSSI);},fail: (err) => {console.error("获取 RSSI 失败:", err);reject(err);}});});}ab2hex(buffer) {// ArrayBuffer转16进度字符串示例const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {return ("00" + bit.toString(16)).slice(-2)})return hexArr.join("").toUpperCase()}delay(ms) {return new Promise(resolve => setTimeout(resolve, ms));}}

同时连接多台蓝牙设备的连接操作方法:

// 封装异步操作函数(uniapp连接蓝牙获取服务需要延迟, 否则会出现无法获取服务情况)   
async connectAndConfigureDevice(deviceId) {try {const bluetooth = new Bluetooth()await bluetooth.connect(deviceId)await bluetooth.delay(1000)await bluetooth.getServices()await bluetooth.delay(1000)await bluetooth.getCharacteristics()await bluetooth.delay(1000)await bluetooth.startNotify()await bluetooth.delay(1000)bluetooth.receiveData()return bluetooth} catch (err) {console.log(err); // 连接出现错误}},async doConnect() {// deviceList 是你保存的每个蓝牙设备信息的数组if (this.deviceList.length > 0) {// 循环连接每个设备for (const device of this.deviceList) {const bluetooth = await this.connectAndConfigureDevice(device.deviceId); // 传入deviceId进行连接if (bluetooth) {console.log("连接成功"); // 这里可以把每个连接成功蓝牙实例(bluetooth)的信息保存起来,建议保存到vuex中,方便后续对某个蓝牙设备的操作}}}}},

ios有一个坑,需要配置后台运行能力,否则切换后台蓝牙会暂停数据上传

这是由于ios系统限制导致的,需要配置后台运行能力,在Hbuilderx中配置即可,如下图

 

 

c29a698f2064bd9586f5826c55b96287.png

 

uniapp官方说明:uni-app官网

 

"audio"表示后台播放音乐能力,"location"表示后台定位能力,'bluetooth-central'表示后台蓝牙功能。

更多后台能力配置参考苹果官网UIBackgroundModes文档

 

 

 

995762ae6a5d72dc93f4ae672aa68d83.png

 


http://www.mrgr.cn/news/76384.html

相关文章:

  • nginx证书流式响应配置
  • Spring Boot实现文件上传与OSS集成:从基础到应用
  • K8S创建云主机配置docker仓库
  • css-50 Projects in 50 Days(4)
  • Python自动化运维DevSecOps与安全自动化
  • hive的tblproperties支持修改的属性
  • 【linux】进程等待与进程替换
  • Pytest-Bdd-Playwright 系列教程(9):datatable 参数的使用
  • vue3:computed
  • 我谈二值形态学基本运算——腐蚀、膨胀、开运算、闭运算
  • web安全漏洞之ssrf入门
  • 优化C++设计模式:用模板代替虚函数与多态机制
  • 二分搜索的三种方法
  • 正则表达式(补充)
  • vue3: ref, reactive, readonly, shallowReactive
  • uniapp: 微信小程序包体积超过2M的优化方法
  • Vue和Vue-Element-Admin(十三):基于vue2比较学习vue3
  • 【AIGC】如何通过ChatGPT提示词Prompt定制个性学习计划
  • vue3: toRef, reactive, toRefs, toRaw
  • linux下编译安装memcached
  • Android ART知多少?
  • 《抽象类和接口》
  • 渗透测试之信息收集 DNS主机发现探测方式NetBIOS 协议发现主机 以及相关PorCheck scanline工具的使用哟
  • 跳房子(弱化版)
  • 芯原科技嵌入式面试题及参考答案
  • cMake编译github中源码