一行代码搞定Weex蓝牙开发

Posted 程序人生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一行代码搞定Weex蓝牙开发相关的知识,希望对你有一定的参考价值。

本文来自CSDN博客,作者ID:彳亍而行的博客

缘起

之所以做这个项目,是因为公司要尝试用Weex做开发,以减少开发工作量,达到一个人搞定前端的目标。设想当中,如果顺利的话,一个人可以同时搞定ios/android两端的开发,尤其是UI方面的开发。传统的工作方式中,同一个UI设计需要iOS/Android两个平台实现基本一致的开发,非常浪费。

Project的优点

设计这个project的时候,考虑到Weex的开发人员一般都是Web开发者,对蓝牙的复杂流程的掌握会比较困难,因此我的目标是,普通的Web开发者,也可以在1-2个小时之内,完成接入一台蓝牙设备的开发。现在看起来,这个目标已经基本上实现了:只用一行代码,就可以实现接入一台蓝牙设备。

下面看一下例子:

一行代码搞定Weex蓝牙开发

}).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()这个方法来说:

模块和技术

在开发的过程中,遇到几个问题:

  1. Native代码如何与Javascript通信

  2. 如何简化使用方式,使得使用者能够方便上手

  3. 如何保证接口的灵活性

下面一个一个来讲。

Native代码如何与JavaScript通信

因为是在Weex框架下开发,所以用到了Weex给的方法。Weex官方给出了互相调用的方法,即WXModuleCallbackWXModuleKeepAliveCallback。这两者的区别在于,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开发具体解释

iOS开发一行代码系列:一行搞定数据库

代码自动生成工具,2小时搞定智能硬件产品Demo

一行代码搞定 font-size 响应式

【springboot+easypoi】一行代码搞定excel导入导出

weex官方demo weex-hackernews代码解读(下)