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

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)
                }
            });
        });
    }
    // 获取服务UUID
    getServices() {
        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);
                    // 找到对应的特征值UUID
                    res.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.kler.cn/a/395976.html

相关文章:

  • R语言贝叶斯分析:INLA 、MCMC混合模型、生存分析肿瘤临床试验、间歇泉喷发时间数据应用|附数据代码...
  • 【算法】二分查找
  • layui的table组件中,对某一列的文字设置颜色为浅蓝怎么设置
  • FBX福币交易所恒指收跌1.96% 半导体股继续回调
  • 跟着尚硅谷学vue2—基础篇4.0
  • AutoDL远程连接技巧
  • 鸿蒙元服务 证书过期替换 ERROR - hap-sign-tool: error: Signature verify failed
  • Spring Boot3 实战案例合集上线了
  • Shell脚本:遍历目录下的文件
  • 深度学习神经网络在机器人领域应用的深度剖析:原理、实践与前沿探索
  • Hive的map/struct/array怎么通过insert插入数据
  • 硬件工程师之电子元器件—二极管(6)之肖特基二极管特性
  • STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56
  • SQL进阶写法
  • 机器视觉和计算机视觉的区别
  • 提升前端性能:如何优化多个异步请求的执行效率Promise.all()
  • python isinstance(True, int)
  • Web_前端_HTML入门学习的案例案例1
  • 《动手学深度学习》中d2l库的安装以及问题解决
  • 免费送源码:Java+Springboot+MySQL Springboot多租户博客网站的设计 计算机毕业设计原创定制
  • 深度学习:transpose_qkv()与transpose_output()
  • taro框架h5项目打包后页面空白 解决办法
  • 【系统、用户提示词区别】
  • AI大模型(二):AI编程实践
  • 深度学习:广播机制
  • 差分数组-实现区间强度算法