小程序蓝牙模块踩坑
此篇文章为我在做用到小程序蓝牙模块的项目过程中总结的经验。
一、小程序蓝牙连接流程梳理:
1.第一步,调用wx.openBluetoothAdapter,初始化蓝牙适配器;
2.第二步,调用wx.getBluetoothAdapterState,获取本机蓝牙适配器状态;
3.第三步,进行蓝牙连接,安卓系统直接调用wx.createBLEConnection连接蓝牙,使用示例:
wx.createBLEConnection({
deviceId,//设备mac地址
success (res) {
console.log(res)
}
})
如果是ios系统,则需先调用wx.startBluetoothDevicesDiscovery和wx.getBluetoothDevices搜索附近蓝牙设备并匹配,用mac地址匹配设备名称,获取其deviceId,拿到这个deviceId才能使用wx.createBLEConnection连接到蓝牙设备:
wx.startBluetoothDevicesDiscovery({
success(res) {
//获取搜索到的设备
wx.getBluetoothDevices({
success(res) {
var devices = res.devices;//设备列表
var realMac = '';
//匹配
if (devices.length > 0) {
for (var i = 0; i < devices.length; i++) {
if (devices[i].name === _this.data.mac) {
realMac = devices[i].deviceId;//这个才是ios设备真正的deviceId
break;
}
}
}
}
});
}
});
4.第四步,调用wx.getBLEDeviceServices获取蓝牙设备所有服务;
5.第五步,调用wx.getBLEDeviceCharacteristics获取某个服务的特征值;
6.第六步,调用wx.notifyBLECharacteristicValueChange启用蓝牙设备特征值变化时的 notify 功能;
7.第七步,调用wx.writeBLECharacteristicValue向蓝牙设备中写入二进制数据;
8.第八步,调用wx.onBLECharacteristicValueChange监听蓝牙设备特征值变化;
9.最后调用wx.closeBLEConnection断开蓝牙连接、调用wx.closeBluetoothAdapter关闭蓝牙模块。
二、项目中遇到的问题和解决方法总结:
区分ios和安卓,蓝牙需要做不同处理:
进行蓝牙连接时,安卓系统直接调用wx.createBLEConnection连接蓝牙,ios系统需先调用wx.startBluetoothDevicesDiscovery和wx.getBluetoothDevices搜索附近蓝牙设备并匹配,用mac地址匹配设备名称,获取其deviceId,拿到这个deviceId后才使用wx.createBLEConnection连接蓝牙设备。在这一步之前可以使用var system = wx.getSystemInfoSync();判断到当前系统类型,if(system == 'ios')时,搜索蓝牙设备,if(system == 'android')时直接通过mac地址连接蓝牙设备。
ios搜索并匹配蓝牙设备不一定能够一次成功:
ios搜索并匹配蓝牙设备不一定能够一次成功,处理方法,多匹配几次:
//链式处理
this.openBluetoothAdapter()
.then((res) => {
//初始化蓝牙设备成功后,执行下一步获取本机蓝牙适配器状态
return this.getBluetoothAdapterState();
}).then((res) => {
//获取本机蓝牙适配器状态成功后,执行下一步搜索附近蓝牙设备、获取以及匹配
return this.serachAndGetBluetooth();
}).then((res) => {
//第一次匹配蓝牙设备成功后,执行接下来的连接操作
return this.iosContinueConnect();
},(reason) => {
//匹配蓝牙设备失败,持续匹配,三次之后之后,若还匹配不到,则提示失败
console.log('第一次匹配失败,进行第二次匹配');
this.serachAndGetBluetooth().then((res) => {
//第二次匹配成功
return this.iosContinueConnect();
}, (reason) => {
console.log('第二次匹配失败,进行第三次匹配');
this.serachAndGetBluetooth().then((res) => {
//第三次匹配成功
return this.iosContinueConnect();
}, (reason) => {
//第三次仍匹配失败,结束搜索,关闭蓝牙设备
//停止搜索设备
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("结束搜索")
}
});
//关闭蓝牙模块
wx.closeBluetoothAdapter({
success(res) {
console.log('已关闭蓝牙模块');
}
});
console.log('匹配蓝牙设备失败');
})
})
})
})
})
})
//搜索附近的蓝牙外围设备、获取、并匹配
serachAndGetBluetooth: function () {
var _this = this;
var p = new Promise(function (resolve, reject) {
wx.startBluetoothDevicesDiscovery({
success(res) {
//获取搜索到的设备
wx.getBluetoothDevices({
success(res) {
var devices = res.devices;//设备列表
var realMac = '';
//匹配
if (devices.length > 0) {
for (var i = 0; i < devices.length; i++) {
if (devices[i].name === _this.data.mac) {
realMac = devices[i].deviceId;
break;
}
}
} else {
reject('fail');
console.log('匹配蓝牙设备失败');
}
if (realMac !== '') {
//匹配成功
_this.setData({
deviceId: realMac
});
resolve('success');
console.log('成功匹配蓝牙设备');
//成功后停止搜索设备
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("结束搜索")
}
});
} else {
reject('fail');
console.log('匹配蓝牙设备失败');
}
},
fail(err) {
reject('fail');
console.log('匹配蓝牙设备失败');
}
});
},
fail(err) {
reject('fail');
console.log('搜索蓝牙设备失败');
}
});
});
return p;
},
如果打开蓝牙适配器后立即搜索蓝牙,可能会导致搜索失败
有一个问题,如果打开蓝牙适配器后立即搜索蓝牙,可能会导致搜索失败,所以最好等待两秒后再进行搜索,则上段代码可优化为:
//链式处理
this.openBluetoothAdapter()
.then((res) => {
//初始化蓝牙设备成功后,执行下一步获取本机蓝牙适配器状态
return this.getBluetoothAdapterState();
}).then((res) => {
//获取本机蓝牙适配器状态成功后,执行下一步搜索附近蓝牙设备、获取以及匹配
return this.serachAndGetBluetooth();
}).then((res) => {
//第一次匹配蓝牙设备成功后,执行接下来的连接操作
return this.iosContinueConnect();
},(reason) => {
//匹配蓝牙设备失败,持续匹配,三次之后之后,若还匹配不到,则提示失败
console.log('第一次匹配失败,进行第二次匹配');
this.serachAndGetBluetooth().then((res) => {
//第二次匹配成功
return this.iosContinueConnect();
}, (reason) => {
console.log('第二次匹配失败,进行第三次匹配');
this.serachAndGetBluetooth().then((res) => {
//第三次匹配成功
return this.iosContinueConnect();
}, (reason) => {
//第三次仍匹配失败,结束搜索,关闭蓝牙设备
//停止搜索设备
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("结束搜索")
}
});
//关闭蓝牙模块
wx.closeBluetoothAdapter({
success(res) {
console.log('已关闭蓝牙模块');
}
});
console.log('匹配蓝牙设备失败');
})
})
})
})
})
})
//搜索附近的蓝牙外围设备、获取、并匹配
serachAndGetBluetooth: function () {
var _this = this;
var p = new Promise(function (resolve, reject) {
setTimeout(() => {
wx.startBluetoothDevicesDiscovery({
success(res) {
//获取搜索到的设备
wx.getBluetoothDevices({
success(res) {
var devices = res.devices;//设备列表
var realMac = '';
//匹配
if (devices.length > 0) {
for (var i = 0; i < devices.length; i++) {
if (devices[i].name === _this.data.mac) {
realMac = devices[i].deviceId;
break;
}
}
} else {
reject('fail');
console.log('匹配蓝牙设备失败');
}
if (realMac !== '') {
//匹配成功
_this.setData({
deviceId: realMac
});
resolve('success');
console.log('成功匹配蓝牙设备');
//成功后停止搜索设备
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("结束搜索")
}
});
} else {
reject('fail');
console.log('匹配蓝牙设备失败');
}
},
fail(err) {
reject('fail');
console.log('匹配蓝牙设备失败');
}
});
},
fail(err) {
reject('fail');
console.log('搜索蓝牙设备失败');
}
});
},2000);
});
return p;
},
ios蓝牙连接优化方案
ios搜索并匹配蓝牙设备这一步耗时较长,可以在第一次匹配到蓝牙设备时,记录下设备的deviceId,第二次就可以直接使用这个deviceId进行连接,而不需要再进行搜索操作,提高效率。
//如果deviceId已保存,可直连
if (_this.data.deviceId){
this.openBluetoothAdapter()
.then((res) => {
//初始化蓝牙设备成功后,执行下一步获取本机蓝牙适配器状态
return this.getBluetoothAdapterState();
}).then((res) => {
//已经获取过一次devicId,使用旧的deviceId,直接连接
return this.iosContinueConnect();
})
}else{
//如果如果deviceId未保存,说明是第一次连接,搜索附近蓝牙设备
//链式处理
this.openBluetoothAdapter()
.then((res) => {
//初始化蓝牙设备成功后,执行下一步获取本机蓝牙适配器状态
return this.getBluetoothAdapterState();
}).then((res) => {
//获取本机蓝牙适配器状态成功后,执行下一步搜索附近蓝牙设备、获取以及匹配
return this.serachAndGetBluetooth();
}).then((res) => {
//第一次匹配蓝牙设备成功后,执行接下来的连接操作
return this.iosContinueConnect();
},(reason) => {
//匹配蓝牙设备失败,持续匹配,三次之后之后,若还匹配不到,则提示失败
console.log('第一次匹配失败,进行第二次匹配');
this.serachAndGetBluetooth().then((res) => {
//第二次匹配成功
return this.iosContinueConnect();
}, (reason) => {
console.log('第二次匹配失败,进行第三次匹配');
this.serachAndGetBluetooth().then((res) => {
//第三次匹配成功
return this.iosContinueConnect();
}, (reason) => {
//第三次仍匹配失败,结束搜索,关闭蓝牙设备
//停止搜索设备
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("结束搜索")
}
});
//关闭蓝牙模块
wx.closeBluetoothAdapter({
success(res) {
console.log('已关闭蓝牙模块');
}
});
console.log('匹配蓝牙设备失败');
})
})
})
})
})
})
//搜索附近的蓝牙外围设备、获取、并匹配
serachAndGetBluetooth: function () {
var _this = this;
var p = new Promise(function (resolve, reject) {
setTimeout(() => {
wx.startBluetoothDevicesDiscovery({
success(res) {
//获取搜索到的设备
wx.getBluetoothDevices({
success(res) {
var devices = res.devices;//设备列表
var realMac = '';
//匹配
if (devices.length > 0) {
for (var i = 0; i < devices.length; i++) {
if (devices[i].name === _this.data.mac) {
realMac = devices[i].deviceId;
break;
}
}
} else {
reject('fail');
console.log('匹配蓝牙设备失败');
}
if (realMac !== '') {
//匹配成功
_this.setData({
deviceId: realMac
});
resolve('success');
console.log('成功匹配蓝牙设备');
//成功后停止搜索设备
wx.stopBluetoothDevicesDiscovery({
success(res) {
console.log("结束搜索")
}
});
} else {
reject('fail');
console.log('匹配蓝牙设备失败');
}
},
fail(err) {
reject('fail');
console.log('匹配蓝牙设备失败');
}
});
},
fail(err) {
reject('fail');
console.log('搜索蓝牙设备失败');
}
});
},2000);
});
return p;
},
一次连接,多次与蓝牙设备交互
项目中有个需求,第一次发送数据包给蓝牙设备后,等待蓝牙设备回应,再进行第二次发送数据包,这就要求监听两次蓝牙设备回应。
正确步骤是:开启notify功能->第一次写数据->监听->第二次写数据->监听->蓝牙回应后结束本次蓝牙连接
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: deviceId,
serviceId: notifyServicweId,
characteristicId: notifyCharacteristicsId,
success: function (res) {
console.log('启用低功耗蓝牙设备特征值变化时的 notify 功能成功');
//使用定时器异步调用顺序执行,否则可能导致收不到设备返回的特征值变化信息
//发包
for (let i = 0; i < commonds.length; i++) {
let hex = commonds[i];
let typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
}));
let buffer = typedArray.buffer;
setTimeout(function() {
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: writeServicweId,
characteristicId: writeCharacteristicsId,
value: buffer,
success: function (res) {
if(i == commonds.length-1 ) {
//注意要发完最后一包后才进行接下来的操作
wx.onBLECharacteristicValueChange(function (characteristic) {
//监听到蓝牙回应
//第二次写数据
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: writeServicweId,
characteristicId: writeCharacteristicsId,
value: '00F0',
success: function (res) {
wx.onBLECharacteristicValueChange(function (characteristic) {
//监听成功后结束蓝牙连接
wx.closeBLEConnection({
deviceId,
success(res) {
console.log('已断开蓝牙连接');
//关闭蓝牙模块
wx.closeBluetoothAdapter({
success(res) {
console.log('已关闭蓝牙模块');
}
});
}
});
});
},fail(err){
console.log(err)
}
})
});
}
},fail(err) {
console.log(err)
}
});
}, 110);
}
}
});