uni-app、微信小程序低功耗蓝牙开发及使用

引导

  • 今天在这里记录分享一下低功耗蓝牙的使用方法和需要注意的地方
  • 如果使用的微信小程序原生开发,使用方法是一样的,只需要把所有uni换成wx就行
  • 例 wx.openBluetoothAdapter({})
  • 文章中会详细写出每个api的注意事项和配套使用方法 供大家参考 希望可以帮到大家
1. 初始化蓝牙
  • 使用之前一定要进行初始化,蓝牙初始化之后才可以进行下面一系列操作
  • 就算使用的是低功耗蓝牙,也需要初始化
	uni.openBluetoothAdapter({
    
    
		// 蓝牙初始化成功执行
		success:(res)=>{
    
    
			// 这里成功之后就不用管了,直接执行就行
		},
		// 蓝牙初始化失败执行
		fail:(err)=>{
    
    
			// 初始化失败之后有需求的话可以进行一些处理
			// 没有需求的也不用管
			// 一般情况下,还是需要分析一下原因的,这用用户和自己就知道为什么失败了
			if(err.errCode == 10001){
    
    
				// 这种情况是未打开蓝牙 就需要提示用户检测蓝牙并打开
				uni.showToast({
    
    
	              title: "请检查蓝牙是否开启!",
	              icon: "none",
	              duration: 2000,
	            });
			}
			// 我这里只演示这一个,其他的状态可进入官网进行查看
			//  uni-app  https://uniapp.dcloud.io/api/system/bluetooth.html
			// 微信原生  https://developers.weixin.qq.com/miniprogram/dev/api/device/bluetooth/wx.openBluetoothAdapter.html
		}
	})
2. 查找(搜寻)附近蓝牙
  • 蓝牙初始化成功之后就可以进行查询附近蓝牙了
	uni.startBluetoothDevicesDiscovery({
    
    
		success:()=>{
    
    
			// 调用成功之后就开始查询附近蓝牙了
			// 成功之后可调用这个函数,每次查询到新的蓝牙设备就会调用
			// 这个函数使用不使用都可以,不影响查询的结果
			uni.onBluetoothDeviceFound((devices)=>{
    
    
				console.log(devices)  // 蓝牙设备信息
				// 返回的数据是ArrayBuffer格式的需要进行转换,不然咱也看不懂都是些啥
				// ArrayBuffer 的转换后面会详细写出来
			})
			// 接着进行 成功之后建议等个几秒钟之后再获取查询到的列表
			// 我这里就是用定时器做了一个两秒的延迟
			setTimeout(()=>{
    
    
				uni.getBluetoothDevices({
    
    
					success:(res)=>{
    
    
						// res.devices 为 查询到的蓝牙设备列表
						// 拿到结果之后,进行处理
						// 首先进行过滤一下查询的列表,会出现很多未知设备这类的,这里就直接把它们给排除掉了,只留下有完整名称的设备
						var arr = []
						res.devices.forEach((element)=>{
    
    
							if(element.name !== "位置设备") {
    
    
								arr.push(element)	
							}
						})
						// 筛选之后在进行判断是否有正常的蓝牙设备  
						// 当然你也可以查看一下被筛选掉的设备是否有你所使用的设备,如果有你可以去掉筛选 或者自己定义筛选条件
						if(arr.length == 0){
    
    
							uni.showToast({
    
    
		                      title: "未查询到可用设备,请重新扫描",
		                      duration: 1000,
		                      icon: "none",
		                    });
						}
						// 最后这个arr就是所查到的列表
						console.log(arr)
						// 不管查没查到一定要使用 stopBluetoothDevicesDiscovery 停止查询
						// 不管查没查到一定要使用 stopBluetoothDevicesDiscovery 停止查询
						// 不管查没查到一定要使用 stopBluetoothDevicesDiscovery 停止查询
						uni.stopBluetoothDevicesDiscovery()
					}
				})
			},2000)
		}
	})
3. 连接蓝牙
  • 现在蓝牙设备列表也有了,往下做的就是连接蓝牙
	// 为了能否顺利的连接蓝牙 可以先查询一下是否有设备已经连接蓝牙了
	// 手环这一类的设备 可能会对程序造成干扰 会一直显示设备已经连接
	uni.getConnectedBluetoothDevices({
    
    
		success:(res)=>{
    
    
			// 因为我为了蓝牙的连接的稳定性,就做了这一步
			// 大家使用的过程中可以省略这一步直接进行蓝牙设备
			// 但是不确定是否可以正常进行蓝牙连接, 大家可以尝试一下
			// 如果返回的列表不等于空,就代表已经有设备连接
			if(res.devices.length !== 0) {
    
    
				// 这里就需要提示用户蓝牙已连接
				uni.showModal({
    
    
				  title: "提示!",
                  content: "当前蓝牙已于id为"+res.devices[0].deviceId+"的设备连接,是否断开连接",
                  success: (row)=>{
    
    
                  	// 用户点击确定执行
                  	if (row.confirm) {
    
    
                  		// 用户点击确定之后把当前连接的蓝牙断开
                  		uni.closeBLEConnection({
    
    
                  			// 一定要传入当前连接蓝牙的deviceId
                  			deviceId: deviceId,
                  			success:()=>{
    
    
                  				// 到这里就已经断开成功了,再次点击就可以进行连接了
                  				uni.showToast({
    
    
			                        title: "连接已断开!",
			                        icon: "none",
			                        duration: 2000,
		                      	});
                  			},
                  			fail:(err)=>{
    
    
                  				// 走到这就是断开失败了,可以进行操作提示用户或者自己查看
		                      uni.showToast({
    
    
		                        title: err.errMsg,
		                        icon: "none",
		                        duration: 2000,
		                      });
                  			}
                  		})
                  	}else{
    
    
                  		// 用户取消之后不需要做任何操作
                  		console.log('用户点击了取消')	
                  	}
                  }
                });
			}else {
    
    
				// 当前未处于已连接状态就开始进行连接,没有连接的情况下就可以直接连接蓝牙
				uni.createBLEConnection({
    
    
					// 连接的时候一定传入要连接蓝牙的deviceId
					deviceId:deviceId,
					// 这里可以选择设置一个延迟,如果延迟时间过了没有连接成功就直接提示报错
					timeout:5000,
					success:(res)=>{
    
    
					// 连接成功之后可以再次进行查询一下当前连接的蓝牙信息,保存下载,后面方便使用
						uni.getConnectedBluetoothDevices({
    
    
							success:(devicess)=>{
    
    
								// devicess就是当前已经连接的蓝牙列表
								// 在这判断一下有没有蓝牙,如果有就证明确实已经连接成功
								if(devicess.devices[0]){
    
    
									// 到这里就可以提示用户成功,并且吧蓝牙信息保存下来方便后面使用
									console.log(devicess.devices[0]) // 蓝牙信息
								}else {
    
    
									// 如果走这里面就是没有蓝牙设备,就要查看一下,看看是否真的连接成功了	
								}
							}	
						})
					},
					fail:(err)=>{
    
    
						// 在这里查看连接失败的信息,判断为什么连接失败
						console.log(err)
					}
				})
			}
		}
	})
4. 蓝牙通讯
  • 至此以上操作蓝牙已经连接,但是还没有进行通讯
  • 下面就是蓝牙的通讯
  • 也可以说蓝牙能通讯了,才算是正在的连接成功
	// 蓝牙接收数据主要使用的api是开启监听(uni.notifyBLECharacteristicValueChange)
	// 但是开启监听是需要几个特殊的值才能开启
	// 所以开启之前我们需要获取这个值 
	// deviceId  蓝牙deviceId,蓝牙信息中包含的有
	// serviceId 蓝牙服务值,根据蓝牙deviceId获取
	// characteristicId 蓝牙特征值 根据serviceId 获取
	// 首先根据deviceId  获取到服务值 serviceId 
	uni.getBLEDeviceServices({
    
    
		deviceId:deviceId, // 获取服务值,需要传入deviceId
		success:(res)=>{
    
    
			// res.services 返回一个数组,里面包含着支持不同的通讯方式的serviceId  一般为三个左右,也有可能更多
			console.log(res.services)
			// 拿到之后根据自己所需要的去保存serviceId,在后面使用
			// 这里建议多试试,说不定那个可以用,又或者某个不能用
			// 获取到之后就可以去拿着获取到的serviceId和deviceId去获取特征值
			uni.getBLEDeviceCharacteristics({
    
    
				deviceId:deviceId, // 传入获取到的deviceId
        		serviceId:serviceuuid, // 传入获取到的serviceuuid
        		success:(ress)=>{
    
    
        			// ress里面就是获取到的蓝牙特征值
        			// 注意:根据传入serviceuuid的不同获取到的特征值也是不一样的,
        			// 特征值分为,可读、可写、可通知等几个类型的,根据自己想要的操作选择特征值
        			console.log.(res.characteristics)
        		},
        		fial:(err)=>{
    
    
        			// 一般来说只要参数对,就不会报错
        		}
			})
		},
		fial:(err)=>{
    
    
			// 一般来说只要	deviceId 对,就不会报错
		}
	})

5. 启用 特征值 变化监听

  • 什么是启用特征值变化监听,其实就是开启接收蓝牙设备发送过来的数据,你不启用就接收不到蓝牙数据
  • 经上所诉,启用这个监听就变得重重之重,不启用,上面一系列操作白搭
  • 启用特征值监听需要用到 deviceId、serviceuuid、characteristicId(特征值)
// 这里所声明介绍一下所用到的东西
// deviceId 就是上面蓝牙设备的deviceId
// serviceuuid 就是上面根据蓝牙设备获取到的serviceuuid 
// characteristics 就是上面根据 deviceId 和 serviceuuid 获取到的
// characteristics 是一个数组里面包含着多个特征值, 根据使用去拿响应的特征值

// 我这里没有直接使用,而是进行一个循环判断,判断这么多的特征值中那个是符合要求的
  var characteristicId;
  var i = 0
  then.characteristiclist.forEach((element) => {
    
    
    if (element.properties.notify == true) {
    
    
      if (i == 0) {
    
    
        characteristicId = element.uuid;
        i++;
      }
    }
  });
  // 为什么循环
  // 因为开启uni.notifyBLECharacteristicValueChange需要特征值是需要固定的,我就直接判断写入了
    uni.notifyBLECharacteristicValueChange({
    
    
      deviceId: deviceId,
      serviceId: serviceuuid,
      characteristicId: characteristicId,
      state: true,
      success: () => {
    
    
        console.log('监听启动成功');
		// 启用成功之后就可以在uni.onBLECharacteristicValueChange 中获取到蓝牙设备发送的数据
      },
    });

6. 接收数据

  • 到此整个蓝牙通讯就已经完成,接下来就是获取蓝牙发送的数据了
  • 这里所用到的函数方法都会在最后一一列出
uni.onBLECharacteristicValueChange((res)=>{
    
    
	console.log(res.value)  
	// 这就是蓝牙发送的数据 但是现在的数据,还不能直观的看出来是什么,还需要进行一些列转换才能直观查看
	console.log(this.buf2str(res.value))
	// 经过 this.buf2str 转换之后就可以直观查看 蓝牙返回的信息
})

7. 向设备写入数据

  • 通讯当然不是单方面的通讯,我们也能向设备发送一些东西
  • 下面就介绍一下想蓝牙发送数据
// 所用到的就是上面获取到的
// 但是特征值跟上面不一样,需要支持可写
      var characteristicId;
      var i = 0;
      then.characteristiclist.forEach((element) => {
    
    
        if (element.properties.write == true) {
    
    
          if (i == 0) {
    
    
            characteristicId = element.uuid;
            i++;
          }
        }
      });
      uni.writeBLECharacteristicValue({
    
    
        deviceId: deviceId,
        serviceId: serviceuuid,
        characteristicId: characteristicId,
        value: this.string2buffer(row),
        success: () => {
    
    
          // console.log('指令写入成功');
          // 写入成功之后在onBLECharacteristicValueChange里面应该是有反馈的
        }
      })
 // this.string2buffer 把16进制字符串转换成buffer之后进行写入,我也忘了直接传入字符串可不可以使用,应该是不行,可以尝试一下,不行就按着我的来也行

8. 所用到的js函数

   
    // 因为我所写入的指令带有一些特殊字符,我是手动转成16进制之后在进行的转换ArrayBufer
    // 如果需要直接字符串转ArrayBufer,百度一下你就知道
    // 将16进制字符串转换成ArrayBufer
    string2buffer (str) {
    
    
      return new Uint8Array(
        str.match(/[\da-f]{2}/gi).map(function (h) {
    
    
          return parseInt(h, 16);
        })
      ).buffer;
    }
   // ArrayBufer 转字符串
   buf2str (buffer) {
    
    
      let encodedString = String.fromCodePoint.apply(
        null,
        new Uint8Array(buffer)
      );
      let decodedString = decodeURIComponent(escape(encodedString));
      //没有这一步中文会乱码
      return decodedString;
    },

  • 使用过程中 如遇到其它问题,尽可联系我
  • 大家一起进步 一起改bug
  • 纯手工制作,望多多支持
  • 你的点赞就是我,制作的动力

猜你喜欢

转载自blog.csdn.net/weixin_45243487/article/details/125789751