最近一段时间,因为产品的需要我做了一个基于低功耗蓝牙设备的Android应用,其中碰到了一些困难,使我深深体会到Android开发的难处:不同品牌,不同型号和不同版本之间的差异使得Android应用适配成为一个痛点,尤其是跟硬件相关的,每个厂商在实现Android API的时候,或多或少都会有些差别。这些区别,有些是明显的Bug,有些则是对API理解的差异造成的。

我的开发是基于Android 4.3+ 标准BLE API。Android 4.3之前厂商自己实现的API不在讨论之列。Android 5.0对BLE API进行了改进,但由于基于Android 5.0的智能设备还没有普及,所以我也没有针对Android 5.0进行适配。希望新的API实现可以不仅仅是语义上的统一,在这背后的行为上也应该是一致的,

在这里我分享一些在Android BLE开发过程中遇到的奇怪的事,希望后来者不要走我走过的弯路......

命令执行的顺序

机型 - 红米 1S, Android 4.4.2   / 华为 荣耀6, Android 4.4.2

在BLE设备连接并且做完Service Discovery之后,下一步要做的就是读写设备的Characteristic了,通常在连接后需要读写几个Characteristic。因为我之前做过苹果的开发,这些对BLE读写的命令都是异步,可以并发的,底层实现应该会有一个queue来缓存硬件没有实际执行的命令。于是我想当然的就按照以前的做法实现了对Characteristic的读写,并且在红米 1S上成功运行。可是当我用华为手机测试的时候出错了,我要的数据没有读出来。Debug后发现底层报错,在执行第二个命令时,出现了“有命令在执行中”的错误。请教了伟大的Stack Overflow后才知道,原来有些Android的实现是没有底层的Command Queue的。我在应用层实现了一个简单的Queue,只有当前一个BLE命令执行完成后才进行下一个命令的执行,华为手机的问题就解决了!当然在已经实现了Command Queue的手机上,新的方法也是没有问题的。

所以,同样是实现了Android API,不同的厂商对这背后行为的理解是不同的。如果Google能够不仅对API的语义进行规范,同时也对其行为进行统一,那该多完美!

设备的搜索(Scan)

机型 - Samsung S3 Android 4.3 (机锋ROM)

Android提供了两个API做BLE设备的搜索,一个是带Service UUID过滤,一个不带过滤。我最初的实现选择了带UUID过滤的API,这样效率应该会稍稍高一些吧。在红米1S,华为荣耀6以及魅族MX2上都工作正常,可以搜索到我指定的设备。然而三星S3却无法搜索到任何设备,我百思不得其解,只得再次求助Stack Overflow - 原来不是所有的设备都支持带UUID过滤的设备搜索(怎么会这样?)。我只好使用不带UUID过滤的API了,然后在应用层通过设备名称来过滤我想要的结果。这样一切都好了...吧?

红米1S的奇葩行为

机型 - 红米 1S, Android 4.4.2

俗话说拆了东墙补西墙,用来形容Android开发再恰当不过了,好不容易为一款手机做完了改动,结果原来工作正常的机型却又出了问题。上面为三星S3做过的改动就是一个例子:三星倒是OK了,可是原来一切安好的红米1S却收不到从设备发来的Notification了(读写Characteristic正常)。一开始我很抓狂,不知道为什么红米突然就不工作了,Debug底层也没有报错。万般无奈,只好一点点回退,最后终于发现问题出现在Scan设备的API使用上:如果我用不带UUID过滤的API,红米1S就无法收到从设备发来的Notification!多么奇葩的行为!在红米上我可以搜寻到设备,可以连接,可以发现Service,可以读写Characteristic,却单单无法收到Notification。当我改成带Service UUID过滤的API后,一切就都好了!好吧,这个Bug一般人真的很难理解了,就交给小米去解决吧。

可是我该怎么办呢?只有hack一下,判断机型和版本号,使用不同的BLE Scan API了。太丑陋了!

三星的连接问题

机型 - Samsung Note 2, Android 4.3

三星手机是我做适配时出问题最多的机型了,可能的原因是三星在很早之前就支持了低功耗蓝牙,并且在Android 4.3之前提供了它自己的BLE API。当Android 4.3标准BLE API出来之后,三星做了API的适配,但并不完美。由于条件所限,我们只测试了三星比较老的一些机型,感觉问题还是比较多的,最新的机型以及ROM版本应该会好很多(我们还没有收到关于S5的问题报告)。除了上面讲到的BLE Scan的问题,三星手机对BLE设备的连接也有比较特别的要求:(来自Stack Overflow)某些三星手机在进行BLE连接时,需要在UI thread里调用相应的API。我的应用场景是当手机搜索到设备后自动进行设备连接,在实际的使用中我发现即使是把connect device调用放在UI Thread里,三星手机也是经常不工作的。最后,我在连接设备之前加了一个延时,它就工作了。。。至于是怎么发现的就不啰嗦了,说多了都是泪啊。

Android的BLE API

安卓对于BLE的支持相比iOS来说确实差了许多:API是基于传统Bluetooth API改进的,不支持BLE peripheral模式,在一些API的行为上没有iOS友好,等等。Android 5.0对BLE API进行了重构,并且支持了BLE peripheral模式,希望会大大改善BLE在安卓系统上的体验。

最后贴一段代码,这是用来设置接收设备Notification的,如果不调用writeDescriptor那段代码,notification就不工作。可是谷歌你就不能把它封装在setCharacteristicNotification里么?这个坑不知道害了多少码农啊。。。

  1. /**
  2. * Enables or disables notification on a give characteristic.
  3. *
  4. * @param characteristic Characteristic to act on.
  5. * @param enabled If true, enable notification.  False otherwise.
  6. */
  7. public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
  8. boolean enabled) {
  9. if (mBluetoothAdapter == null || mBluetoothGatt == null) {
  10. Log.w(TAG, "BluetoothAdapter not initialized");
  11. return false;
  12. }
  13. mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
  14. if (enabled && CHARACT_UUID_BATT_LEVEL.equals(characteristic.getUuid().toString()))
  15. {
  16. Log.i(TAG, "setCharacteristicNotification");
  17. BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
  18. UUID.fromString());
  19. descriptor.setValue("00002902-0000-1000-8000-00805f9b34fb");
  20. mBluetoothGatt.writeDescriptor(descriptor);
  21. }
  22. return true;
  23. }

Android低功耗蓝牙(BLE)开发的一点感受的更多相关文章

  1. Android 低功耗蓝牙BLE 开发注意事项

    基本概念和问题 1.蓝牙设计范式? 当手机通过扫描低功耗蓝牙设备并连接上后,手机与蓝牙设备构成了客户端-服务端架构.手机通过连接蓝牙设备,可以读取蓝牙设备上的信息.手机就是客户端,蓝牙设备是服务端. ...

  2. 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体解释

    转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体 ...

  3. 【转】Android低功耗蓝牙应用开发获取的服务UUID

    原文网址:http://blog.csdn.net/zhangjs0322/article/details/39048939 Android低功耗蓝牙应用程序开始时获取到的蓝牙血压计所有服务的UUID ...

  4. Android低功耗蓝牙(蓝牙4.0)——BLE开发(上)

    段时间,公司项目用到了手机APP和蓝牙设备的通讯开发,这里也正好对低功耗蓝牙(蓝牙4.0及以后标准)的开发,做一个总结. 蓝牙技术联盟在2010年6月30号公布了蓝牙4.0标准,4.0标准在蓝牙3.0 ...

  5. Android蓝牙BLE开发,扫描、连接、发送和读取信息;

    1.BLE开发权限 Android蓝牙BLE开发须打开蓝牙权限和6.0位置权限: <uses-permission android:name="android.permission.B ...

  6. Android低功耗蓝牙(BLE)使用详解

    代码地址如下:http://www.demodashi.com/demo/13390.html 与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设备 ...

  7. 低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端

    低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端 Android对外模模式(peripheral)的支持 从Android5.0开始才支持 关键术语和概念 以下是关键BLE术语和 ...

  8. 深入浅出低功耗蓝牙(BLE)协议栈

    深入浅出低功耗蓝牙(BLE)协议栈 BLE协议栈为什么要分层?怎么理解蓝牙"连接"?如果蓝牙协议只有ATT没有GATT会发生什么? 协议栈框架 一般而言,我们把某个协议的实现代码称 ...

  9. 深入浅出讲解低功耗蓝牙(BLE)协议栈

    详解BLE连接建立过程https://www.cnblogs.com/iini/p/8972635.html 详解BLE 空中包格式—兼BLE Link layer协议解析https://www.cn ...

随机推荐

  1. Java运算符(一)equals方法与“==”

    超类Object的equals只是比较两者之间的引用对象是否相同,这一点跟操作符“==”是一样的. 在基本数据类型中,“==”用于比较两者之间的值(内容)是否相等. 在引用类型中,“==”用于比较两者 ...

  2. JavaScript 作用域和变量提升

    本文是这篇文章的简单翻译. 如果按照下面的代码按照JavaScript程序的执行方式执行,alert函数会显示什么? var foo = 1; function bar() { if (!foo) { ...

  3. Excel列表部分列表隐藏与取消隐藏

    Excel列表部分列表隐藏与取消隐藏 2014-2-19 隐藏:选中需要隐藏的列(选中A.B.C....),右键单击所选部分,选择"隐藏"即可. 取消隐藏:从A选中至所见表格最后的 ...

  4. ZOJ3582:Back to the Past(概率DP)

    Recently poet Mr. po encountered a serious problem, rumor said some of his early poems are written b ...

  5. 【HDOJ】1180 诡异的楼梯

    bfs+优先队列.wa了N次,才发现可以停留等待楼梯变换方向. #include <iostream> #include <queue> #include <cstdio ...

  6. Super Phyllis(穷举+搜索)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2723 题意:给出一些字符串u,v,代表u-&g ...

  7. 【http】

    var qs = require('querystring') require('http').createServer(function(req, res) { //res.writeHead(20 ...

  8. sql截取数据库数字字段内容

    round(columnName, precision) 四舍五入 trunc(columnName, precision) 强制截断

  9. 推荐一个Xcode插件: KSImageNamed (自动补全图片文件名称, 并显示图片大小)

    http://www.csdn.net/article/2014-05-04/2819586-the-best-xcode-plugins 5. KSImageNamed KSImageNamed是一 ...

  10. Flash3D引擎:Away3D 4.1 Alpha版介绍

    转自:http://www.cnblogs.com/njflash/archive/2013/01/31/2886912.html Away3D团队和基金会很高兴地宣布首次发布下一个主要的Away3D ...