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

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

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

代码:

javascript 复制代码
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));
    }

}

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

javascript 复制代码
// 封装异步操作函数(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中配置即可,如下图

uniapp官方说明:uni-app官网

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

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

相关推荐
子非衣12 分钟前
MySQL修改JSON格式数据示例
android·mysql·json
openinstall全渠道统计3 小时前
免填邀请码工具:赋能六大核心场景,重构App增长新模型
android·ios·harmonyos
双鱼大猫4 小时前
一句话说透Android里面的ServiceManager的注册服务
android
双鱼大猫4 小时前
一句话说透Android里面的查找服务
android
双鱼大猫4 小时前
一句话说透Android里面的SystemServer进程的作用
android
双鱼大猫4 小时前
一句话说透Android里面的View的绘制流程和实现原理
android
双鱼大猫5 小时前
一句话说透Android里面的Window的内部机制
android
双鱼大猫5 小时前
一句话说透Android里面的为什么要设计Window?
android
双鱼大猫5 小时前
一句话说透Android里面的主线程创建时机,frameworks层面分析
android
苏金标6 小时前
android 快速定位当前页面
android