乐趣区

关于前端:快来解锁小程序蓝牙开发技能

微信小程序中很早就反对了蓝牙能力,看过不少的文档,晓得大略的流程和能实现的成果,然而因为始终没有像样的实战我的项目导致也没有正经的开发上线过,本次缘于接到了一个外包我的项目,那就顺道记录一下开发的过程及遇到的问题。

理论我的项目的成果很简略,两个页面,一个页面建设连贯,一个页面展现数据,大略就是下图所示。

老板说,这个简略版本就 2 个页面,1000 块吧。

想了想,这貌似没啥问题,预计都不必一天就搞定了,暗喜 ing。

然而理论的状况远远超出预算的开发工夫。当初我的项目曾经公布上线了,回顾算了一下断断续续的开发工夫差不多要了 2 天工夫,这样一算着实不开心了,不过也就当加深教训。以下记录理论遇到的问题,开发框架:uniapp,蓝牙的调用和微信小程序中根本一样。

建设连贯

建设连贯根本是这个步骤:

  • 初始化蓝牙
  • 开始搜查左近设施
  • 在搜查左近设施回调中找到要连贯的设施
  • 连贯设施
  • 进行搜寻左近设施

具体实现的过程

初始化蓝牙,这里有一个留神点,建设连贯后可能须要从新连贯,所以初始化之前须要将现有的连贯断开,可调用敞开蓝牙模块断开,否则无奈搜寻到要连贯到设施。

// 敞开蓝牙模块
uni.closeBluetoothAdapter({success(res) {
    // 初始化蓝牙
    uni.openBluetoothAdapter({success(res) {console.log('初始化蓝牙胜利')
      },
      fail(err) {console.log('初始化蓝牙失败')
      }
    })
  }
})

开始搜查左近设施并在搜寻左近设施的回调中找到要连贯的设施,搜寻的回调中会蕴含蓝牙的名称和设施 ID,能够通过名称辨认要连贯的蓝牙,设施 ID 用于连贯蓝牙,这个办法比拟消耗系统资源,连贯胜利须要被动调用敞开蓝牙搜寻。

// 开始搜查左近设施
uni.startBluetoothDevicesDiscovery({success() {
    // 开启监听回调
    uni.onBluetoothDeviceFound(found)
  }
})

function found(res) {if (res.devices[0] && res.devices[0].name.includes('XXX')) {
    // 连贯设施
    uni.createBLEConnection({deviceId: res.devices[0].deviceId,
      success(res) {
        // 进行搜寻
        uni.stopBluetoothDevicesDiscovery()}
    })
  }
}

监听音讯

下面建设连贯胜利了,因为本次连贯的是低功耗蓝牙,后续还须要监听数据回传和数据写入,最终须要调用 notifyBLECharacteristicValueChange 启用蓝牙低功耗设施特征值变动时的 notify 性能,这个办法还须要两个参数,蓝牙特色的 UUID(characteristicId)和 蓝牙特色对应服务的 UUID(serviceId)。

获取蓝牙特色对应服务的 UUID(serviceId):

uni.getBLEDeviceServices({
  deviceId,
  success(res) {// serviceId},
})

基于获取到的 serviceId 持续获取 characteristicId,这里须要留神一下返回的 characteristicId 是在一个数组中的,外面有对应的读写性能的形容,后续依据读写理论状况应用不同的值,不确定的就找硬件开发确认一下。

uni.getBLEDeviceCharacteristics({
  deviceId,
  serviceId,
  success(res) {// characteristicId}
})

最初就是开启音讯监听,启用蓝牙低功耗设施特征值变动时的 notify 性能,订阅特色。另外,必须先启用 notifyBLECharacteristicValueChange 能力监听到设施 characteristicValueChange 事件。

uni.notifyBLECharacteristicValueChange({
  state: true,
  deviceId, // 设施 id
  serviceId, // 监听指定的服务
  characteristicId, // 监听对应的特征值
  success(res) {// 监听音讯变动}
})

监听音讯变动,返回的 res.value 就是须要应用的值,然而这个值的格局是 ArrayBuffer,须要进一步转化应用。

uni.onBLECharacteristicValueChange(res => {ab2hex(res.value)
})

// ArrayBuffer 转 16 进制字符串
ab2hex(buffer) {
  const hexArr = Array.prototype.map.call(new Uint8Array(buffer),
    function(bit) {return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join('')
}

数据写入

到这里咱们就能获取到数据回传了,然而失常操作中还有数据的写入,通过写入不同的指令进行相干的性能操作或者获取不同的数据。这里同样的要留神一点就是写入的数据也是要 ArrayBuffer 格局的,在写入前要留神进行转换。

const typedArray = new Uint8Array(hexStr.match(/[\da-f]{2}/gi).map(function(h) {return parseInt(h, 16)
}))
const buf = typedArray.buffer

uni.writeBLECharacteristicValue({
  deviceId,
  serviceId,
  characteristicId,
  value: buf,
  success() {console.log('writeBLECharacteristicValue success')
  }
})

另外须要留神的是数据写入时的回传数据不会返回在以后办法的回调中,还是在下面的 onBLECharacteristicValueChange 特征值变动事件中,通过具体的回传字符进行辨别以后的操作行为。

后记

上面是一些踩坑的记录,如果没有这么多坑也不会节约这么多的工夫,如果你也是第一次接手这类的我的项目心愿能够对你有所帮忙。

数据格式

前端与蓝牙协定的通信形式不再和平时与后端调用接口那样,在与硬件共事沟通的工夫肯定要沟通分明。首先数据传递不是 string 或 json 之类,而是 ArrayBuffer,而后就是对应传递的字符内容,本次通信的格局是 16 进制且长度为 16 位,但在 JS 中理论要发送一段长度为 32 的字符串并转换成 ArrayBuffer 能力应用。比方接口文档指令 0x04,实例要发送的却是 A1A10400000000000000000000000000,针对这样的状况如有不确定的要和硬件共事踊跃沟通。

数据转换

文档中波及一些数据应用的转换如下所示意:

数据 1 = data[9] * 256 + data[10]
刚开始不了解,认为是有什么非凡的逻辑,前面才晓得就是 16 进制转换成 10 进制。但这在 JS 中有更简略的转换形式。留神:这里的所取的下标都是对应两个字符。

举例:16 进制字符 0x1234

按下面的转换则是 parseInt('12', 16) * 256 + parseInt('34', 16) 等于 4660,JS 间接应用 parseInt 转换 parseInt('0x1234') 或者 parseInt('1234', 16),以 0x 结尾的字符,parseInt 默认按 16 进制解析,最终的后果都是 4660。

这里还波及到一个高下位转换的问题,我这里遇到的是高位在前,低位在后,暂不须要额定解决,理论开发中是否须要进行转换要单方沟通好。

数据应用

本次须要应用的数据如下面数据转换中所援用格局,理论一个残缺的数据是由两个下标的值组成,再转换到 16 进制字符中就是 4 位字符。所以每次转换都是要 4 个字符一组,因波及多个数据取值,且还有前后的有效数据须要进行排除。最终代码如下所示:

const oData = ab2hex(res.value).slice(2).replace(/(.{4})/g, '$1,').split(',')
for(var i = 3; i < oData.length; i++) {if(oData[i] != '0000' && oData[i]) {// 无效数据应用}
}

最初

到此本文就完结了,记录了一下微信小程序蓝牙开发过程以及遇到的问题,心愿对你有帮忙。看完本文如果感觉有用,记得点个赞反对,珍藏起来说不定哪天就用上啦~

专一前端开发,分享前端相干技术干货,公众号:南城大前端(ID: nanchengfe)

退出移动版