一行代码搞定Weex蓝牙开发
Posted 程序人生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一行代码搞定Weex蓝牙开发相关的知识,希望对你有一定的参考价值。
本文来自CSDN博客,作者ID:彳亍而行的博客
之所以做这个项目,是因为公司要尝试用Weex做开发,以减少开发工作量,达到一个人搞定前端的目标。设想当中,如果顺利的话,一个人可以同时搞定ios/android两端的开发,尤其是UI方面的开发。传统的工作方式中,同一个UI设计需要iOS/Android两个平台实现基本一致的开发,非常浪费。
设计这个project的时候,考虑到Weex的开发人员一般都是Web开发者,对蓝牙的复杂流程的掌握会比较困难,因此我的目标是,普通的Web开发者,也可以在1-2个小时之内,完成接入一台蓝牙设备的开发。现在看起来,这个目标已经基本上实现了:只用一行代码,就可以实现接入一台蓝牙设备。
下面看一下例子:
}).then(data => {
var deviceID = data[0];
var serviceID = data[1];
var characteristics = data[2];
for (var i = 0; i < characteristics.length; i++) {
var characteristicID = characteristics[i]['UUID'];
if (characteristicID=="your-characteristic-UUID")
{//listen to value change of characteristic listenToValueChangeOfCharacteristic(deviceID, serviceID,
characteristicID,function(data){ console.log(data); }); } } });
嗯,的确是一行代码哦!虽然比较长:-D
用的是javascript的Promise技术,所以能够一气呵成,从打开蓝牙->扫描设备->连接设备->发现服务->发现特征->读/写/监听特征。对于开发者来讲,只要有蓝牙设备的协议文档,就可以仿照这个写法,很快就可以完成。
而且project的文档很详细,就在week-bluetooth.js里。具体就不讲了,因为很简单易懂。贴一点代码来看看。比如对于discoverDevice()
这个方法来说:
在开发的过程中,遇到几个问题:
Native代码如何与Javascript通信
如何简化使用方式,使得使用者能够方便上手
如何保证接口的灵活性
下面一个一个来讲。
因为是在Weex框架下开发,所以用到了Weex给的方法。Weex官方给出了互相调用的方法,即WXModuleCallback
和WXModuleKeepAliveCallback
。这两者的区别在于,WXModuleKeepAliveCallback
可以被作为变量保存下来,长期使用。具体的文档在这里:http://weex.apache.org/cn/references/ios-apis.html
Weex还提供了一种global event方式的通信,本项目没有采用。考虑到可能会有连接多台设备、以及其它复杂情况,global event可能难以处理,并且native端使用的delegate,很适合用callback的方式,因此整个实现过程都不用global event。
native端的接口设计,模仿了微信小程序的蓝牙接口设计方式。由于Weex通信方式的限制,做了一定的调整。
微信小程序的蓝牙接口文档在这里:https://mp.weixin.qq.com/debug/wxadoc/dev/api/bluetooth.html
如何简化使用方式,使得使用者能够方便上手
蓝牙通信是一个蛮麻烦的事情:数据传输有UDP的特性,发出去了对方不一定能收到,收到了也不一定有返回;时常会因为各种原因断开连接;步骤也很复杂,先搜索,再连接,连接完了要搜索services,然后搜索某个service下的characteristics,根据不同的characteristic的用处,或读或写。Native端用的是delegate的方式,连接的时候各种delegate callback,一般不研究个1、2天,还真搞不清楚。
对于这种情况,我通过以下的方式来避免。
首先,用code block方式代替delegate,这样代码组织就更明晰了。这部分主要是在设计Native接口上进行的处理。
但是这样还不够,虽然用了block,但在使用的过程中,会遇到callback hell。下面是刚开始时Javascript调用的方式:
const wx = weex.requireModule('wx-ble');
var that = this; wx.openBluetoothAdapter(function(res){ // success var services = [] wx.startBluetoothDevicesDiscoveryWithServices(services,function(res){ var deviceID = res['peripheral']['deviceID']
var deviceName = res['peripheral']['name']
var index = deviceName.indexOf("your-ble-name");
if (index != -1){ wx.createBLEConnectionWithDeviceID(deviceID, function(res){ wx.stopBluetoothDeviceDiscovery(function(res){ }) wx.getBLEDeviceServicesWithDeviceID(deviceID, function(res){ that.target = res
for(var i=0;i<res.length;i++){
var serviceID = res[i] that.target = that.target + serviceID if (serviceID=="FFF0") { that.target = that.target + ",," + serviceID wx.getBLEDeviceCharacteristicsWithDeviceID(deviceID,
serviceID, function(res){ that.target = res['characteristics'] var chars = res['characteristics'] for (var i = 0; i < chars.length; i++) { var characteristicID = chars[i] if (characteristicID=="FFF2") {//write characteristic var value = "5A5A"; wx.writeBLECharacteristicValueWithDeviceID(
deviceID, serviceID, characteristicID, value, function(res){ }) }
if (characteristicID=="FFF1")
{//nofity characteristic wx.onBLECharacteristicValueChange(function(res)
{ var value = res['value'] that.target = value }) wx.notifyBLECharacteristicValueChangeWithDeviceID(
deviceID, serviceID, characteristicID, true, function(res){ that.target = res }) } } }) } } }); }) } },) }) }
嗯,至少有10个callback嵌套。我用了Javascript的Promise来处理这个问题。我的理解中,Promise是一种用于统一处理if/else代码块的方法,在多线程和条件嵌套情况下使用起来很方便。当然Promise也有局限,后面会讲到。
用Promise包装后的调用方法,就是刚开始的例子了。对比一下,区别还是蛮大的,逻辑清晰多了。
还有一个,蓝牙通信是基于”0101”这样的二进制数据来进行的,但一般来说,向蓝牙设备写数据的时候,都会将之转换成16进制数据,比如用”5A”来表示”01011010”。因此在接口的设计中,开发者可以直接用”5A5A”这样的字符串来向蓝牙设备中写数据,这样就简单许多。在读数据的时候,返回的则是直接的”01011010”这样的字符串,这是考虑到许多蓝牙设备的返回结果,每一位都有特定的含义,”01”字符串的方式更方便进行解析。
如何保证接口的灵活性
蓝牙开发中的概念还是蛮多的,开发过程中有一些一般情况下其实用不到,比如蓝牙设备的信号强度等。所以我在设计的时候,从实用的角度考虑,简化了一些数据的格式,保留了主要的数据,以使得开发起来更加方便。在一些关键的地方,我保留了自定义的接口,比如过滤设备、过滤service等。这样一般在开发基本上已经算是足够了。
设计接口的时候,受到了Web Bluetooth API的启发,它的实现方式也是Promise。有兴趣的可以了解一下:https://developers.google.com/web/updates/2015/07/interact-with-ble-devices-on-the-web
另外,在设计接口的时候,也参考了BabyBluetooth这个项目:https://github.com/coolnameismy/BabyBluetooth
目前只有iOS部分实现了,比较遗憾。以后有机会肯定还是要实现Android部分的,要不然不方便使用。
Promise的特性是一次性调用,而蓝牙通信其实有一些”Stream”的意思,导致了一些局限性。比如,发现了某一台蓝牙设备之后,如果resolve了,那么后面即使再发现一台设备,也无法再次调用resolve。后面准备通过结合callback的方式,弥补这个缺陷。
还有一些尚待完善的地方,比如当蓝牙断开连接时,需要通知到Javascript,这些异常事件的处理;另外,支持多设备同时连接等等,也可能会考虑进来。
以上是关于一行代码搞定Weex蓝牙开发的主要内容,如果未能解决你的问题,请参考以下文章
使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体解释