前置问题:每当连接完蓝牙并且会启用notify监听。在这时一但断开蓝牙并且重新连接,notify功能会被二次启用,第一次启用的notify会在后台运行,无法被关闭。除非将整个app给“杀死”。在上述情况下,我们给蓝牙发送一条下行指令,notify会接收到两条相同的上行指令。如果我们的业务逻辑是每次接收到一条上行指令,然后要去做对应的业务操作。在这种情况下,我们会做出几次相同的业务操作。这就会导致一些莫名其妙的bug。
解决方法:把蓝牙封装成单独的js模块,利用单例模式来创建蓝牙类。利用isNotify参数来判断是否开启过notify功能。因为断开重连后的蓝牙不重新开启notify功能,notify功能是无法使用的。所以我们添加一个notifyCount来记录notify功能重启过几次,这样我们就可以清楚每次发送一条下行数据后,会有几条重复的上行数据被接收。
封装的ble_class.js蓝牙模块代码:
class blue_class {
static instance = null; // 静态属性,用于存储单例
// 私有构造函数,防止外部通过 new 关键字创建实例
constructor() {
// 初始化蓝牙相关的状态或变量
this.bluetoothStatus = null; // 蓝牙状态
this.isNotify=false;//用于防止重复启动notify功能
this.notifyCount=0; //用于判断启动了几次notify功能
}
// 静态方法,用于获取蓝牙管理器的实例
static getInstance() {
if (!blue_class.instance) {
// 如果没有实例,则创建一个新的实例
blue_class.instance = new BLE_Class(); // 注意这里使用了 private constructor
}
return blue_class.instance;
}
// 初始化蓝牙适配器
// 注意:这个方法应该是公开的,但不应该在构造函数中调用
initBluetoothAdapter() {
// 这里使用uni.openBluetoothAdapter等API来初始化蓝牙适配器
uni.openBluetoothAdapter({
success: (res) => {
console.log('蓝牙适配器初始化成功', res);
this.bluetoothStatus = 'open'; // 更新蓝牙状态
},
fail: (err) => {
console.error('蓝牙适配器初始化失败', err);
this.bluetoothStatus = 'error'; // 更新蓝牙状态
}
});
}
// ArrayBuffer转16进度字符串示例
ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
}
//监听设备发送数据
onBLECharacteristicValueChange(){
uni.onBLECharacteristicValueChange((sjRes) => {
var resData=this.ab2hex(sjRes.value);
uni.$emit('xx',resData);
})
}
// 启用 notify 功能
startNotice(uuid) {
// 预防重复启动
if(this.isNotify)
{
console.log('已经启用过 notify 功能');
}
else
{
uni.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: uuid.deviceUUID,
serviceId: uuid.serviceUUID,
characteristicId: uuid.notifyUUID,
success:(res)=> {
// store.state.notyfiyFlagList.push(uuid);
console.log('成功启用 notify 功能',uuid);
this.isNotify=true;
// 启动一次notify,就加1
this.notifyCount=this.notifyCount+1;
this.onBLECharacteristicValueChange();
},
fail:(res)=> {
console.log('启用 notify 功能失败',res)
}
});
}
}
}
export default blue_class;
示例蓝牙连接页面模块:
<script setup>
import blue_class from '../xxx/xxx/xx.js';
const a=blue_class .getInstance();
// 蓝牙连接请参考官方文档
function connectBle(){
uni.createBLEConnection({
deviceId:connectId,
success(res) {
// 获取蓝牙服务
getBLEDeviceServices(connectId);
},
fail(err) {
}
})
}
// 初始化蓝牙服务
function openBluetoothAdapter(){
a.initBluetoothAdapter();
}
// 启用监听
function startNotify(){
a.startNotice(uuid);
// 用于记录这是第几次重复监听
let count=0;
uni.$on('xx',function(data){
console.log('上行数据', data.toUpperCase());
count++;
if(count==a.notifyCount)
{
// 使用最后一次监听的数据,然后清零计数器
count=0;
//业务逻辑....
}
})
}
onUnload(()=>{
//关闭监听
uni.$off("xx");
})
</script>