zhichi_admin 发表于 2018-1-15 17:57:19

「微信新功能」小程序如何连接蓝牙设备

小程序在线学习平台:http://school.jisuapp.cn/
小程序如何连接蓝牙设备?我实现的小程序模块自动连接(根据需要,可改手动),是在小程序初始化完成时开始自动调用执行。大致流程:
[*]开启蓝牙适配;
[*]获取蓝牙适配器状态,判断设备蓝牙是否可用;
[*]判断蓝牙适配器可用时开启扫描蓝牙设备和开启获取已连接的蓝牙设备;
[*]如果开启扫描蓝牙设备失败 5s 后,自动再次开启扫描;
[*]开启扫描蓝牙设备成功后,开启监听已扫描的设备;
[*]如果已扫描到的新设备,包含特定名称规律,则开始连接该设备;
[*]开启获取已连接蓝牙设备,成功后,连接包含特定名称规律的设备;
[*]两者都无法搜索到相应设备,则等待 5 s,重新搜索;
[*]开始连接某设备时停止扫描设备,停止循环获取已连接设备;
[*]连接成功后停止扫描设备,停止循环获取已连接设备。
下面,我们一步步来完成这个流程。手把手教你做小程序蓝牙连接
1. 开启连接app.js 的 onLaunch() 方法中,我们调用开启连接 this.startConnect();,弹出提示框,开启适配。如果失败,则提示设备蓝牙不可用,同时开启蓝牙适配器状态监听。startConnect: function () {var that = this;wx.showLoading({    title: '开启蓝牙适配'});wx.openBluetoothAdapter({    success: function (res) {      console.log("初始化蓝牙适配器");      console.log(res);      that.getBluetoothAdapterState();    },    fail: function (err) {      console.log(err);      wx.showToast({      title: '蓝牙初始化失败',      icon: 'success',      duration: 2000      })      setTimeout(function () {      wx.hideToast()      }, 2000)    }});wx.onBluetoothAdapterStateChange(function (res) {    var available = res.available;    if (available) {      that.getBluetoothAdapterState();    }})}

2. 获取本机蓝牙状态调用 this.getBluetoothAdapterState() 获取本机蓝牙适配器状态,判断是否可用,available 为 false,则为用户没有开启系统蓝牙。同时,判断程序还没有开始搜索蓝牙设备,调用 this.startBluetoothDevicesDiscovery() 开始扫描附近的蓝牙设备,以及 this.getConnectedBluetoothDevices(),获取本机已配对的蓝牙设备。getBluetoothAdapterState: function () {var that = this;wx.getBluetoothAdapterState({    success: function (res) {      var available = res.available,      discovering = res.discovering;      if (!available) {      wx.showToast({          title: '设备无法开启蓝牙连接',          icon: 'success',          duration: 2000      })      setTimeout(function () {          wx.hideToast()      }, 2000)      }      else {      if (!discovering) {          that.startBluetoothDevicesDiscovery();          that.getConnectedBluetoothDevices();      }      }    }})}


3. 开始搜索新设备开始搜索蓝牙设备 startBluetoothDevicesDiscovery(),提示蓝牙搜索。startBluetoothDevicesDiscovery: function () {var that = this;wx.showLoading({    title: '蓝牙搜索'});wx.startBluetoothDevicesDiscovery({    services: [],    allowDuplicatesKey: false,    success: function (res) {      if (!res.isDiscovering) {      that.getBluetoothAdapterState();      }      else {      that.onBluetoothDeviceFound();      }    },    fail: function (err) {      console.log(err);    }});}

4. 获取已配对的蓝牙设备需要注意的是,参数 services(Array)是必填的,但是官方示例中以及各种坑爹 demo 里从没见过有谁填写。不填写这个属性此方法,将无法获取到任何已配对设备。如果要调用此方法,则代表需要连接特定设备,并且知道该设备的一个主服务 serviceId。如暂时不知道这个 ID,可以先手动连接一次想要连接的设备,然后获取 service 列表,记录属性 primary 为 true 的值至少一个。getConnectedBluetoothDevices: function () {var that = this;wx.getConnectedBluetoothDevices({    services: ,    success: function (res) {      console.log("获取处于连接状态的设备", res);      var devices = res['devices'],      flag = false,      index = 0,      conDevList = [];      devices.forEach(function (value, index, array) {      if (value['name'].indexOf('FeiZhi') != -1) {          // 如果存在包含FeiZhi字段的设备          flag = true;          index += 1;          conDevList.push(value['deviceId']);          that.deviceId = value['deviceId'];          return;      }      });      if (flag) {      this.connectDeviceIndex = 0;      that.loopConnect(conDevList);      }      else {      if (!this.getConnectedTimer) {          that.getConnectedTimer = setTimeout(function () {            that.getConnectedBluetoothDevices();          }, 5000);      }      }    },    fail: function (err) {      if (!this.getConnectedTimer) {      that.getConnectedTimer = setTimeout(function () {          that.getConnectedBluetoothDevices();      }, 5000);      }    }});}

5. 处理搜索功能开启失败的情况如果搜索功能启动失败,回到第 2 步,重新检查蓝牙适配器。如果可用,开启蓝牙搜索功能成功后开启发现附近蓝牙设备事件监听:this.onBluetoothDeviceFound()。
onBluetoothDeviceFound: function () {var that = this;console.log('onBluetoothDeviceFound');wx.onBluetoothDeviceFound(function (res) {    console.log('new device list has founded')    console.log(res);    if (res.devices) {      var name = res.devices['name'];      if (name != '') {      if (name.indexOf('FeiZhi') != -1) {          var deviceId = res.devices['deviceId'];          that.deviceId = deviceId;          console.log(that.deviceId);          that.startConnectDevices();      }      }    }})}此方法可自定义过滤一些无效的蓝牙设备比如 name 为空的,或是个人产品开发中需要过滤设备名称不含有特定规律字符串的设备。
6. 自动连接设备在第 5 步中发现了某个想配对的设备,则获取到该设备的 deviceId,然后开始配对该设备 this.startConnectDevices()。startConnectDevices: function (ltype, array) {var that = this;clearTimeout(that.getConnectedTimer);that.getConnectedTimer = null;clearTimeout(that.discoveryDevicesTimer);that.stopBluetoothDevicesDiscovery();this.isConnectting = true;wx.createBLEConnection({    deviceId: that.deviceId,    success: function (res) {      if (res.errCode == 0) {      setTimeout(function () {          that.getService(that.deviceId);      }, 5000)      }    },    fail: function (err) {      console.log('连接失败:', err);      if (ltype == 'loop') {      that.connectDeviceIndex += 1;      that.loopConnect(array);      }      else {      that.startBluetoothDevicesDiscovery();      that.getConnectedBluetoothDevices();      }    },    complete: function () {      console.log('complete connect devices');      this.isConnectting = false;    }});}
开启连接后,为了避免出现冲突,一旦开启连接,则需要终止扫描附近蓝牙设备、终止读取本机已配对设备。
7. 连接成功后握手连接成功后,使用 this.getService(deviceId) 接口,获取设备的所有服务。getService: function (deviceId) {var that = this;// 监听蓝牙连接wx.onBLEConnectionStateChange(function (res) {    console.log(res);});// 获取蓝牙设备service值wx.getBLEDeviceServices({    deviceId: deviceId,    success: function (res) {      that.getCharacter(deviceId, res.services);    }})}

8. 读取服务的特征值
getCharacter: function (deviceId, services) {var that = this;services.forEach(function (value, index, array) {    if (value == that.serviceId) {      that.serviceId = array;    }});wx.getBLEDeviceCharacteristics({    deviceId: deviceId,    serviceId: that.serviceId,    success: function (res) {      that.writeBLECharacteristicValue(deviceId, that.serviceId, that.characterId_write);      that.openNotifyService(deviceId, that.serviceId, that.characterId_read);    },    fail: function (err) {      console.log(err);    },    complete: function () {      console.log('complete');    }})}

9. 意外处理如果扫描到的设备中没有想要连接的设备,可以尝试使用系统蓝牙手动配对,然后再小程序中调用 getConnectedBluetoothDevices() 获取本机已配对的蓝牙设备,然后过滤设备(可能获取多个已配对的蓝牙设备)。将已获取的蓝牙设备 deviceId 列表放入到一个数组中,然后调用自定义方法 this.loopConnect();。思路:通过递归调用获取已配对蓝牙设备的 deviceId,如果获取到了就去连接,如果 devicesId 为空,说明上传调用 getConnectedBluetoothDevices() 时,获取到的已配对设备全部连接失败了。这时候,我们需要开启重新获取已配对蓝牙设备的状态,并开始扫描附近蓝牙设备。loopConnect: function (devicesId) {var that = this;var listLen = devicesId.length;if (devicesId) {    this.deviceId = devicesId;    this.startConnectDevices('loop', devicesId);}else {    console.log('已配对的设备小程序蓝牙连接失败');    that.startBluetoothDevicesDiscovery();    that.getConnectedBluetoothDevices();}}

10. 自动连接蓝牙设备startConnectDevices('loop', array) 方法,是当获取已配对蓝牙设备进行连接时调用。其中的处理逻辑上文已经贴出,意思就是在连接失败后 fail 方法里累加一个全局变量,然后回调 loopConnect(array) 方法。
11. 手动连接上文介绍的方法是为了直接自动连接,如果不需要自动连接,可在使用方法getBluetoothDevices() 将会获取到已扫描到的蓝牙设备的列表。开发者可以做个页面显示出设备名,点击该设备开始连接。

需要注意的事项
[*]that.serviceId 是在初始化时设置的,由于对需要连接设备的主服务 serivceId 和各种特征值都是已知的因此可以这样做。如果不可知可以做一个扫描方法自己检查特征值的用途。
[*]连接成功后的 writeBLECharacteristicValue 和 openNotifyService 操作需要注意,如果同时开启这两项操作要先调用 wirte 再开启 notify(原因未知,个人心得)。
[*]3、经人提醒,还可以再完善一下在 onBlueToothAdapterStateChange() 监听蓝牙适配器状态,以此判断连接过程中、连接后用户开关了设备蓝牙。如果判断到关了蓝牙,发出开启蓝牙的提示;如果监听到开启了,就重新回到第 1 步。


页: [1]
查看完整版本: 「微信新功能」小程序如何连接蓝牙设备