微信小程序蓝牙开发调通一点心得

蓝牙程序的调用并没有想象中跟其他接口对接那么简单,除了调用开启链接后,还需要商家蓝牙api提供的特定服务uuid以及特征码uuid才能正常进行数据交汇通信

下面简单说明下微信小程序的蓝牙调用:

1.wx.openBluetoothAdapter 初始化蓝牙

   wx.openBluetoothAdapter({
      success: (res) => {
        wx.showLoading({
          title: '蓝牙开启成功',
          mask: true
        })
        app.globalData.reboot_ble_bool = false;
       //初始化成功后开始搜索蓝牙设备
        this.startBluetoothDevicesDiscovery();
      },
      fail: (res) => {
        console.error("ble adapter open fail");
        wx.hideLoading();
        wx.showModal({
          title: '提示',
          content: '请确保设备蓝牙功能已打开,且允许微信连接蓝牙,部分机型需要授予微信定位权限',
          showCancel: false,
          complete: () => {
            app.globalData.reboot_ble_bool = true;
            //todo
            wx.navigateTo({
               url: '未打开蓝牙跳转界面',
            });
          }
        });
      }
    })

2.wx.startBluetoothDevicesDiscovery 搜索附近蓝牙设备,获得其参数

     wx.startBluetoothDevicesDiscovery({
        allowDuplicatesKey: true,
        success: (res) => {
          console.log('startBluetoothDevicesDiscovery success', res);
          //注册蓝牙设备发现事件
          this.onBluetoothDeviceFound();
          //设置蓝牙设备发现结束事件
          setTimeout(function(){
            console.log("设备搜索完成时间到了,执行停止搜索");
            _this.stopBleDeviceDiscovery();
          },this.data.deviceDiscoveryDuration);
        },
      })
  1. wx.onBluetoothDeviceFound 监听寻找到新设备的事件
/**
   * 找到设备 回调函数
   * Android 6.0以上需要手机打开定位服务 否则搜不到设备
   */  
  onBluetoothDeviceFound:function() {
    wx.onBluetoothDeviceFound((res) => {
      console.log("device number:"+res.devices.length);
      //会不断出现新设备 可能需要通过rssi强度过滤
      res.devices.forEach(device => {
        //console.log("获得搜索蓝牙的名称:"+device.name);
        //有的设备没有设备名
        if (!device.name || !device.localName) {
         // console.log("device name or localName is null");
          return;
        }
        //过滤其他设备
        if (this.data.deviceFilter && device.name.indexOf(this.data.devicePrefix) !== 0){
          return;
        }
        const foundDevices = this.data.devices;
        const idx = this.inArray(foundDevices, 'deviceId', device.deviceId);
        const data = {};
        if (idx === -1) {
          data[`devices[${foundDevices.length}]`] = device;
        } else {
          data[`devices[${idx}]`] = device;
        }
        console.log(foundDevices.length);
        console.log(foundDevices);
        if(foundDevices.length < 1){
          wx.hideLoading();
        }
         //把上面监听到新设备的信息显示到小程序页面端,并绑定点击按钮事件,用于连接对应蓝牙
        this.setData(data);
      })
    });
  },

4.wx.createBLEConnection 连接对应的连接低功耗蓝牙设备。

  /**
   * 对应设备点击事件
   */
  createBLEConnection(e) {
    const ds = e.currentTarget.dataset;

    const deviceId = ds.deviceId;
    const name = ds.name;
    console.log("开始连接" + name + ":" + deviceId);
    var deviceInfo={id:deviceId,name:name};
    app.globalData.connectedDevice=deviceInfo;
    console.log("开始连接:" + app.globalData.connectedDevice.toString);

    this.stopBleDeviceDiscovery();
    wx.showLoading({
      title: '正在连接',
      mask: true
    });
    var _this = this;
    wx.createBLEConnection({
      deviceId,
      success: (res) => {
        this.setData({
          connected: true,
        //  name,
        //  deviceId,
        })
        _this.getBLEDeviceServices(deviceId);
        //_this.connectComplete();
      }
    });
  },

5.wx.getBLEDeviceServices 获取蓝牙设备所有服务(service)UUID。

这里开始对于没有接触过蓝牙的人来说可能就出现懵逼状态(比如我),前面的步骤都可以按部就班。
通过连接事件wx.createBLEConnection后,这里就会出现很多个服务UUID,我们需要根据商家提供的AIP找到需要的那个进行通信,不然选择了其他的可以连接,但无法自由收发通信。


正常来说有些商家会固定只有一个 isPrimary 为 true.但不排除有这种全为true的商家,此时我们只能根据以下两种情况进行链接:
1.固定的uuid判断,直接通过写死 用 == 来获取

image
2。通过特征码判断获取,这就是下面第6点

6.wx.getBLEDeviceCharacteristics 获取蓝牙设备某个服务uuid中所有特征值(characteristic)。

想要完全进行通信,必须有servuceUUID跟其下的 characteristic中的指定uuid
每个characteristic下也有多个不同的权限

    wx.getBLEDeviceCharacteristics({
      deviceId,
      serviceId,
      success: (res) => {
        console.log('getBLEDeviceCharacteristics success', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let item = res.characteristics[i]
          if (item.properties.read) {
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId: item.uuid,
            })
          }
          console.log("!!!:" + item.uuid);
          if (item.properties.write) {
            this.setData({
              canWrite: true,
            })

            this._deviceUUID = deviceId
            this._serviceUUID = serviceId
            this._characteristicUUID = item.uuid
          }
          if ((item.properties.notify || item.properties.indicate) 
                && item.properties.write 
                && item.properties.read) {

                  this._deviceUUID = deviceId;
                  this._serviceUUID = serviceId;
                  this._characteristicUUID = item.uuid;
                  this._writeUUID = item.uuid;
            console.log("订阅设备:" + this._deviceUUID + ":" + this._serviceUUID + ":" + this._characteristicUUID);
            this.connectComplete();
            console.log("订阅结束:" + res.errCode);
            return;
          }else{
             for(let l = 0; l < venderBLE.venderBLEInformation.length;l++){
              if(serviceId == venderBLE.venderBLEInformation[l].SERVICE_UUID){
                this._deviceUUID = deviceId;
                this._serviceUUID = venderBLE.venderBLEInformation[l].SERVICE_UUID;
                this._characteristicUUID = venderBLE.venderBLEInformation[l].NOTIFY_UUID; //item.uuid;
                this._writeUUID = venderBLE.venderBLEInformation[l].WRITE_UUID;
                this.connectComplete();
                console.log("通过固定特征码跳转:" + res.errCode);
                return;
              }
             }
          }
          console.log("*********");
          console.log(this._deviceUUID);
          console.log(this._serviceUUID);
          console.log(this._characteristicUUID);
          console.log("*********");
        }
      },
      fail(res) {
        console.error('getBLEDeviceCharacteristics', res)
      }
    });
  • 重点说下:item.properties.write
    item.properties.read
    item.properties.notify || item.properties.indicate
    image
    每一个特征码下都要对应的功能权限,有的只能读,有的只能写。而我们要找到那个拥有notifyindicate为true的那个,同时这个具备writeread权限。如果没有只能根据商家提供的api规定来获取不同的characteristicsUUI值进行操作。(比如我现在这个蓝牙模块商家的writeread权限是分开的两个characteristicsUUID),

7.后面的wx.writeBLECharacteristicValue发送数据跟 wx.notifyBLECharacteristicValueChange与wx.onBLECharacteristicValueChange我就不详说了。主要是上面的两点UUID。只有对上了就能进行通信使用

PS: 根据官方文档,目前貌似依旧只能支持低功耗蓝牙模块,也就是说。我们手机开启的蓝牙功能使用该程序来搜索,是搜索不到的。

很棒。 :v:

卧槽。K哥居然给我点赞了