一、开发流程

  1. 流程图:流程图作者原文章

  1. 实现模块顺序

1.1初始化蓝牙模块(打开蓝牙适配器)

初次加载,自动获取获取系统信息,检查蓝牙适配器是否可用

初始化蓝牙,提示打开GPS和蓝牙,开始自动搜索蓝牙设备

1.2搜索周围蓝牙

开始搜索蓝牙设备,定时1s获取搜索到的设备

把搜索到的设备保存在一个数组内,渲染在页面

1.3监听搜索设备

监听5s后停止搜索,并把新设备push到数组进行渲染

显示设备名称和连接按钮

1.4连接目标设备

点击连接按钮创建连接,获取设备信息

连接成功停止搜索,获取已连接蓝牙的服务

1.5获取服务、特征值

连接成功获取蓝牙设备服务和特征值(是否能读写)

1.6开启notify,监听特征值变化

开启监听功能,发送指令后接收设备响应的数据

1.7发送指令、读写数据

设备特征值中写入数据,必须设备的特征支持 write

ArrayBuffer转16进制字符串

1.8断开连接

清空设备名、设备id,关闭蓝牙模块

二、实现模块代码

  1. 初始化蓝牙模块(打开蓝牙适配器)


openBluetoothAdapter() {
        let that = this;
        uni.openBluetoothAdapter({ //初始化蓝牙模块
          success(res) {
            console.log(res, '初始化蓝牙成功');
            uni.onBluetoothAdapterStateChange((res) => { // 监听蓝牙适配器状态变化
              if (!res.available) {
                uni.showModal({
                  title: '温馨提示',
                  content: '蓝牙适配器不可用,请重新启动',
                  showCancel: false
                });
              }
            });
            that.searchBlue(); //开始搜索
          },
          fail(res) {
            console.log(res, '初始化蓝牙失败');
            uni.showToast({
              title: '请检查手机蓝牙是否打开',
              icon: 'none'
            });
          }
        });
      },
  1. 开始搜索周围蓝牙


searchBlue() {
        let that = this;
        uni.startBluetoothDevicesDiscovery({
          // services: [],
          success: (res) => {
            console.log(res, "开始搜索设备");
            uni.showLoading({
              title: '正在搜索设备'
            });
            that.getBluetoothDevices();
          },
          fail: (res) => {
            console.log(res, '搜索失败');
            uni.showToast({
              title: '搜索蓝牙设备失败!',
              icon: 'none'
            });
          }
        });
      },
  1. 获取搜索到的设备


getBluetoothDevices() {
        let that = this;
        setTimeout(() => {
          uni.getBluetoothDevices({ // 获取搜索到的设备
            success: (res) => {
              console.log(res, "搜索到的设备");
              let devicesListArr = [];
              if (res.devices.length > 0) {
                uni.hideLoading(res.devices);
                res.devices.forEach((device) => {
                  if (!device.name && !device.localName) {
                    return;
                  } else if (device.name.substring(0, 2) == 'AA') {
                    devicesListArr.push(device);
                    that.devicesList = devicesListArr;
                    that.isHideList = true;
                    that.watchBluetoothFound(); // 监听搜索到的新设备
                  } else {
                    return
                  }
                });
              } else {
                uni.hideLoading();
                uni.showModal({
                  title: '温馨提示',
                  content: '无法搜索到蓝牙设备,请重试',
                  showCancel: false
                });
                uni.closeBluetoothAdapter({ //关闭蓝牙模块
                  success: (res) => {
                    console.log(res, "关闭蓝牙模块");
                  }
                });
              }
            }
          });
        }, 2000);
      },
  1. 监听搜索设备


watchBluetoothFound() {
        let that = this;
        uni.onBluetoothDeviceFound(function(res) { // 监听搜索到的新设备
          if (String(res.devices.name).substring(0, 2) == 'AA') {
            devicesListArr.push(res.devices);
            that.devicesList = devicesListArr;
            console.log(res.devices, "监听新设备");
          }
        })
      },
  1. 连接目标设备


createBLEConnection(e) {
        let that = this;
        let deviceId = e.currentTarget.dataset.id;
        let connectName = e.currentTarget.dataset.name;
        console.log("正在连接" + connectName);
        uni.showLoading({
          title: '连接中...'
        });
        uni.createBLEConnection({
          deviceId,
          success: (res) => {
            uni.hideLoading();
            that.stopBluetoothDevicesDiscovery(); // 连接成功,停止搜索
            console.log(res, "连接成功");
            if (res.errCode == 0) {
              that.deviceId = deviceId;
              that.connectName = connectName;
              that.isHideConnect = true;
              that.getBLEDeviceServices(deviceId); // 获取服务
            } else if (res.errCode == 10012) {
              uni.showToast({
                title: '连接超时,请重试!'
              });
            }
          },
          fail(error) {
            uni.hideLoading();
            console.log(error, '连接失败');
            uni.showToast({
              title: '连接失败!'
            });
          }
        });
      },
  1. 获取设备所有服务


getBLEDeviceServices(deviceId) {
        let that = this;
        // let serviceId;
        uni.getBLEDeviceServices({
          deviceId,
          success: (res) => {
            console.log(res.services, "获取设备服务");
            for (let i = 0; i < res.services.length; i++) {
              let isPrimary = res.services[i].isPrimary
              let uuid = res.services[i].uuid.substring(4, 8) == 'FE60' 
              if (isPrimary && uuid) {
                this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
                return
              }
            }
          }
        });
      },
  1. 获取特征值


getBLEDeviceCharacteristics(deviceId, serviceId) {
        let that = this;
        uni.getBLEDeviceCharacteristics({ 
          deviceId,
          serviceId,
          success: (res) => {
            console.log(res.characteristics, '获取特征值成功')
            let characteristicId = res.characteristics[0].uuid;
            let writeNews = {
              deviceId,
              serviceId,
              characteristicId
            };
            that.writeNews = writeNews;
            let notifyId = res.characteristics[1].uuid;
            that.notifyBLECharacteristicValueChange(serviceId, notifyId);
          },
          fail(err) {
            console.log(err, "获取失败");
          }
        });
      },
  1. 启用监听特征值变化


notifyBLECharacteristicValueChange(serviceId, characteristicId) {
        let that = this;
        uni.notifyBLECharacteristicValueChange({ // 启用监听设备特征值变化 
          type: 'notification',
          state: true, // 启用 notify 功能
          deviceId: that.writeNews.deviceId,
          serviceId,
          characteristicId,
          success(res) {
            console.log(res, '启用监听成功');
            that.onBLECharacteristicValueChange()
          },
          fail: (err) => {
            console.log(err, "启用监听失败");
          }
        });
      },
  1. 监听特征值变化


onBLECharacteristicValueChange() {
        let that = this;
        uni.onBLECharacteristicValueChange(res => {
          console.log(res, '监听变化成功');
          let resHex = that.ab2hex(res.value)
          console.log('从机响应的数据:', resHex)
        })
      },
  1. 发送、读取数据


writeBLECharacteristicValue(order) { // 向蓝牙设备发送一个0x00的16进制数据
        let that = this;
        let msg = order;
        let buffer = new ArrayBuffer(msg.length / 2); // 定义 buffer 长度
        let dataView = new DataView(buffer); // 从二进制ArrayBuffer对象中读写多种数值类型
        let ind = 0;
        for (var i = 0, len = msg.length; i < len; i += 2) {
          let code = parseInt(msg.substr(i, 2), 16)
          dataView.setUint8(ind, code)
          ind++
        }
        console.log('主机写入的指令:', that.ab2hex(buffer));
        uni.writeBLECharacteristicValue({
          deviceId: that.writeNews.deviceId,
          serviceId: that.writeNews.serviceId,
          characteristicId: that.writeNews.characteristicId,
          value: buffer,
          writeType: 'writeNoResponse',
          success: (res) => {
            console.log(res, '写入数据成功');
            that.onBLECharacteristicValueChange()
          },
          fail: (err) => {
            console.log(err);
          }
        })
      },
  1. 断开连接


closeBLEConnection() {
        let that = this;
        console.log(that);
        uni.closeBLEConnection({
          deviceId: this.deviceId,
          success: () => {
            uni.showToast({
              title: '已断开连接'
            });
            that.deviceId = '';
            that.connectName = '';
            that.isHideConnect = false;
          }
        });
        that.closeBluetoothAdapter();
      },
  1. 关闭蓝牙模块


closeBluetoothAdapter() {
        let that = this;
        uni.closeBluetoothAdapter({
          success: (res) => {
            console.log(res);
            that.devicesList = [];
            that.isHideList = false;
            that.isHideConnect = false;
          }
        });
      },
  1. 停止搜索设备


stopBluetoothDevicesDiscovery() {
        uni.stopBluetoothDevicesDiscovery({
          success(res) {
            console.log(res);
          }
        });
      },
  1. ArrayBuffer转16进制字符串


ab2hex(buffer) {
        var hexArr = Array.prototype.map.call(
          new Uint8Array(buffer),
          function(bit) {
            return ('00' + bit.toString(16)).slice(-2);
          });
        return hexArr.join('');
      },

三、遇到的问题以及解决

问题1:onBLECharacteristicValueChange监听不到响应数据?

解决方法:

1、给onBLECharacteristicValueChange添加延时器;

2、给notifyBLECharacteristicValueChange添加type: 'notification';

3、给writeBLECharacteristicValue添加 writeType: 'writeNoResponse';

4、更换手机设备:Android、IOS设备;

5、查看特征值:read、notify、write、writeNoResponse;

6、分包发送:蓝牙BLE最大支持20个字节发送,因此超过20个字节需要分包发送;

7、遵循硬件文档:使用指定服务,写入、接收分别使用的特征值(成功解决);

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐