uniapp真的是无所不能了,开发Android和ios移动手机端app变得非常简单,加上目前火遍全球的vue设计方式,使我这个以前一个原生开发者(android studio java开发)也投入其中,但是挑战也来了,刚刚接手就是用uniapp开发硬件-----蓝牙通讯。
好在uniapp对于蓝牙支持还不错,但是坑也不少。
特别记录一下。
首先蓝牙通讯也是分支很多,这儿是ble,也就是蓝牙低功耗,目前物联网常用的通讯,当然和普通的蓝牙配对也是完全不同的。
典蓝牙(classic Bluetooth)和低功耗蓝牙(Bluetooth low energy,简称BLE或者LE),两者有什么区别?为什么他们都叫“蓝牙”?Bluetooth low energy和Bluetooth smart两者又有什么区别?我的应用到底该选经典蓝牙技术还是低功耗蓝牙技术?这是很多刚接触蓝牙技术的人经常碰到的问题。
首先,在2010年以前,当我们谈论蓝牙的时候,就是在说经典蓝牙,因为那个时候还没有低功耗蓝牙。经典蓝牙由蓝牙技术联盟(Bluetooth special interest group,简称Bluetooth SIG)提出并维护,每次SIG发布一版新的蓝牙规格时,都会指明规格的版本号,比如说蓝牙规格1.0/2.0等,其中蓝牙1.0大概在1999年左右发布的,蓝牙2.0在2004年发布,蓝牙2.1在2007年发布,蓝牙3.0在2009年发布,他们都是在2010年之前发布的,因此蓝牙1.0/2.0/2.1/3.0都是讲经典蓝牙的,里面没有任何关于低功耗蓝牙的描述。如果你打开蓝牙3.0规格书,你会发现经典蓝牙包括BR,EDR和HS(AMP)三种模式。
简单来说,只要是蓝牙技术联盟(SIG)发布的技术,即可以称为蓝牙技术。2010年,SIG联盟合并了Wibree联盟(注:Wibree联盟由Nokia和Nordic等创立,旨在为手机周边设备寻找一种更低功耗的无线通信技术),并把Wibree联盟提出的低功耗无线技术重新命名为低功耗蓝牙技术(BLE),从此BLE也成了一种蓝牙技术。相应地,2010年发布的蓝牙4.0规格就同时包含经典蓝牙和低功耗蓝牙,也就是说,从蓝牙4.0之后,蓝牙才分经典蓝牙和低功耗蓝牙。其实,“经典蓝牙”这个称谓不是非常专业,它是人民群众为了口头上的方便而创造出来的,在蓝牙4.0规格中,SIG定义了四种蓝牙controller技术:BR,EDR,AMP和LE,也就是说,蓝牙只有一种蓝牙,那就是SIG的蓝牙,而蓝牙技术本身包含四种类型:BR,EDR,AMP和LE,由于LE是2010年才提出的,比较新,因此为了说起来方便,人们把之前的BR/EDR/AMP技术称为经典蓝牙技术。大家千万不要以为蓝牙4.0之后,蓝牙只有LE一种模式!
为了区分所谓的低功耗蓝牙和经典蓝牙,蓝牙4.0发布之初,SIG还特意将Bluetooth low engery对外宣传为Bluetooth smart,而“Bluetooth”继续用来指代经典蓝牙,Bluetooth smart ready则用来表示双模蓝牙(即同时支持经典蓝牙和低功耗蓝牙),所以市面上有很多关于Bluetooth smart,Bluetooth,Bluetooth smart ready的宣传材料,但是这些名字不仅没有起到传播Bluetooth品牌的作用,还让众多消费者和开发者感到混淆,所以后来SIG不再频繁使用Bluetooth smart等名字,更多的是与蓝牙4.0规格对齐,直接使用LE,BR,EDR等名字进行宣传,对外也不再宣传低功耗蓝牙和经典蓝牙的不同,并将两者统一到“Bluetooth(蓝牙)”这个大品牌下面一起宣传。
蓝牙技术联盟(SIG)后续发布的蓝牙4.1/4.2/5.0,都是同时包含低功耗蓝牙和经典蓝牙的。所以大家开发蓝牙应用的时候,一定要搞清楚自己是要开发低功耗蓝牙应用还是经典蓝牙应用,两者的应用场景是不同的。一般而言,经典蓝牙主要应用在蓝牙电话接听,蓝牙耳机,蓝牙音箱等场合,低功耗蓝牙应用在可穿戴设备,IoT智能设备,健身设备,蓝牙鼠标键盘等电池供电场合。当然,经典蓝牙也可以用电池供电,但LE对电池的要求更低,甚至可以用纽扣电池供电,而续航时间却很长,有的LE设备可以达到几年。下图对经典蓝牙和低功耗蓝牙的典型应用场景进行了总结。

需要引起大家注意的是,经典蓝牙和低功耗蓝牙两者物理层调制解调方式是不一样的,所以低功耗蓝牙设备和经典蓝牙设备两者之间是不能相互通信的,选型的时候千万不要搞混,如果主设备是低功耗蓝牙设备,从设备也必须是低功耗蓝牙设备;同样,经典蓝牙的从设备也只能和经典蓝牙的主设备进行通信。不过市场上还有一种双模蓝牙设备,即同时支持低功耗蓝牙和经典蓝牙,比如我们天天用到的手机,手机可以和经典蓝牙设备通信,也可以和低功耗蓝牙设备通信,如前所述,这不代表低功耗蓝牙设备可以和经典蓝牙设备通信,其实手机使用了分时机制来达到同时和低功耗蓝牙设备以及经典蓝牙设备通信的目的,即手机让双模蓝牙芯片不断地在低功耗蓝牙模式和经典蓝牙模式之间进行切换,以同时支持低功耗蓝牙设备和经典蓝牙设备。低功耗蓝牙方案,经典蓝牙方案,还是双模蓝牙方案,大家选型的时候一定要弄明白他们之间的区别,以选择适合自己的蓝牙方案。
Uni-App开发BLE低功耗蓝牙步骤
开发蓝牙很多小伙伴刚开始一头雾水,不知道从何下手,网上可以查的资料少之又少,所以写这篇文章来总结一下BLE低功耗蓝牙开发流程,话不多说,仔细看!!
- 初始化蓝牙 uni.openBluetoothAdapter(OBJECT)
- 开始搜索蓝牙设备 uni.startBluetoothDevicesDiscovery(OBJECT)
- 发现外围设备 uni.onBluetoothDeviceFound(CALLBACK)
- 停止搜寻附近的蓝牙外围设备 uni.stopBluetoothDevicesDiscovery(OBJECT)
- 连接低功耗蓝牙设备 uni.createBLEConnection(OBJECT)
- 获取蓝牙设备所有服务 uni.getBLEDeviceServices(OBJECT)
- 获取蓝牙特征 uni.getBLEDeviceCharacteristics(OBJECT)
- 启用蓝牙设备特征值变化时的 notify 功能 uni.notifyBLECharacteristicValueChange(OBJECT)
- 监听低功耗蓝牙设备的特征值变化 uni.onBLECharacteristicValueChange(CALLBACK)
基本使用步骤我们总结完了,那么接下来就介绍怎么使用
1.初始化蓝牙
这里主要目的就是检测一下手机蓝牙是否打开
uni.openBluetoothAdapter({
success:(res)=> { //已打开
uni.getBluetoothAdapterState({//蓝牙的匹配状态
success:(res1)=>{
console.log(res1,'“本机设备的蓝牙已打开”')
// 开始搜索蓝牙设备
this.startBluetoothDeviceDiscovery()
},
fail(error) {
uni.showToast({icon:'none',title: '查看手机蓝牙是否打开'
}
});
},
fail:err=>{ //未打开
uni.showToast({icon:'none',title: '查看手机蓝牙是否打开'});
}
})
2.开始搜索蓝牙设备
// 开始搜索蓝牙设备
startBluetoothDeviceDiscovery(){
uni.startBluetoothDevicesDiscovery({
success: (res) => {
console.log('startBluetoothDevicesDiscovery success', res)
// 发现外围设备
this.onBluetoothDeviceFound()
},fail:err=>{
console.log(err,'错误信息')
}
})
}
3.发现外围设备
到这个位置就会搜索到设备了
这个地方重点就是获取到了 deviceId 这是连接蓝牙的重要ID,存起来到data里面后面我们会用到
// 发现外围设备
onBluetoothDeviceFound() {
// console.log("zhixing")
uni.onBluetoothDeviceFound((res) => {
// console.log(res)
// ["name", "deviceId"]
// 吧搜索到的设备存储起来,方便我们在页面上展示
if(this.list.indexOf(res.devices[0].deviceId)==-1){
this.list.push(res.devices[0].deviceId)
}
})
}
4.点击选择自己需要连接的设备
在上面搜索到设备之后我们把设备存储到list里面,方便我们在页面展示,然后点击选择我们要连接的设备,吧deviceId传进来,保存起来,说明我们连接的是这个设备,下面还需要用到,我们存到data里面就行
//选择设备连接吧deviceId传进来
createBLEConnection(deviceId){
let thit = this
//data里面建立一个deviceId,存储起来
this.deviceId = deviceId
//连接蓝牙
uni.createBLEConnection({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId:this.deviceId,
success(res) {
//防止在这里面取不到this,古在外面用thit存储了this
thit.stopBluetoothDevicesDiscovery()
console.log(res)
console.log("蓝牙连接成功")
},fail(res) {
console.log("蓝牙连接失败",res)
}
})
},
5.当我们连接成功的时候,一定要停止搜索外围设备,停止,停止,停止
// 停止搜寻蓝牙设备
stopBluetoothDevicesDiscovery(){
uni.stopBluetoothDevicesDiscovery({
success: e => {
this.loading = false
console.log('停止搜索蓝牙设备:' + e.errMsg);
},
fail: e => {
console.log('停止搜索蓝牙设备失败,错误码:' + e.errCode);
}
});
}
6.获取蓝牙设备所有服务
getBLEDeviceServices这个方法里面填一个参数deviceId就是我们刚刚获取到的
成功就会获取到了services uuid 同理也存储起来
等下来获取特征值
注:这个地方使用了setTimeout等待一秒种再去获取,直接获取我们可能出现获取不到的情况
//获取蓝牙的所有服务
getBLEDeviceServices(){
setTimeout(()=>{
uni.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId:this.deviceId,
success:(res)=>{
// console.log("成功",res)
console.log('device services:', res)
//这里会获取到好多个services uuid 我们只存储我们需要用到的就行,这个uuid一般硬件厂家会给我们提供
res.services.forEach((item)=>{
if(item.uuid.indexOf("AE00")!=-1){
this.serviceId = item.uuid;
//进入特征
this.getBLEDeviceCharacteristics()
}
})
}
})
},1000)
},
7.获取蓝牙特征
这里需要穿2个参数了,就是上面的两个id,分别是deviceId、services
这里获取的特征值的uuid才是我们真正需要操作的uuid
//获取蓝牙特征
getBLEDeviceCharacteristics(){
console.log("进入特征");
setTimeout(()=>{
uni.getBLEDeviceCharacteristics({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId:this.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId:this.serviceId,
success:(res)=>{
console.log(res,'特征getBLEDeviceCharacteristics')
this.characteristics = res.characteristics
console.log(this.characteristics)
//循环所有的uuid
// for(let i=0;i<3;i++){
// this.notifyBLECharacteristicValueChange(res.characteristics[i].uuid)
// console.log(res.characteristics[i].uuid)
// console.log(i,'i')
// }
res.characteristics.forEach((item)=>{
if(item.uuid.indexOf("AE02") != -1){
console.log('characteristicId:', item.uuid)
//利用传参的形势传给下面的notify,这里的uuid如果都需要用到,就不用做判断了,建议使用setTimeout进行间隔性的调用此方法
this.notifyBLECharacteristicValueChange(item.uuid)
}
})
},
fail:(res)=>{
console.log(res)
}
})
},1000)
},
8.启用蓝牙设备特征值变化时的 notify 功能
当我们启动notify功能,才能知道我们当前蓝牙的读写状态,
到这里蓝牙连接基本就完成了,然后就是需要自己用到读写操作
“properties”: {
“read”: true, //读
“write”: true, //写
“notify”: true, //广播
“indicate”: false
}
// 启用 notify 功能
notifyBLECharacteristicValueChange(characteristicId){
console.log(characteristicId,'characteristicId')
uni.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId:this.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId:this.serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId:characteristicId,
success:(res)=> {
console.log(res)
// console.log(this.characteristicId)
console.log('notifyBLECharacteristicValueChange success', res.errMsg)
},
fail:(res)=> {
console.log('notifyBLECharacteristicValueChange success2', res.errMsg)
}
})
},
9.再多介绍一个采坑的记录
那就是监听变化这个方法的使用
最开始我是写在了8.启用 notify 功能里面,可我发现只能监听一个,后来我就吧这个监听方法放在了6.获取蓝牙设备所有服务,这个地方可以监听到所有特征值的变化,所以我们的代码改进一下
就成了下面这段,读取成功就会在这个地方监听输出
//获取蓝牙的所有服务
getBLEDeviceServices(){
setTimeout(()=>{
uni.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId:this.deviceId,
success:(res)=>{
// console.log("成功",res)
console.log('device services:', res)
res.services.forEach((item)=>{
if(item.uuid.indexOf("AE00")!=-1){
// this.serviceId = item.uuid;
//存储到状态
this.$store.commit("upserviceId",item.uuid)
console.log(this.serviceId)
// 这里获取回调,读取成功就的值就会在这个地方接收到!!!
uni.onBLECharacteristicValueChange((res)=>{
console.log("监听成功",res)
//res.value是ArrayBuffer类型的,官方给了一个方法转16进制,我们再进行操作
this.shiliu = this.ab2hex(res.value)
})
this.getBLEDeviceCharacteristics()
}
})
}
})
},1000)
}
到这里基本上就完成了蓝牙的连接
自己需要执行读写操作,就在下面读写就行,如果想默认读写操作,就可以在 8.启用 notify 功能 里面进行操作
就到这里了,如果对你有帮助,请点击喜欢