最近一段时间,因为产品的需要我做了一个基于低功耗蓝牙设备的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. android中viewPager+fragment实现的屏幕左右切换(进阶篇)

    Fragment支持在不同的Activity中使用并且可以处理自己的输入事件以及生命周期方法等.可以看做是一个子Activity. 先看一下布局: 1 <LinearLayout xmlns:a ...

  2. Colored Sticks

    poj2513:http://poj.org/problem?id=2513 题意:就是求一个欧拉回路. 题解:本题是判断欧拉通路是否存在,但是如果是用map的话就会超时,这里采用了trie树,有发现 ...

  3. 更改JENKINS主目录

    在部署时,发现直接启动WAR包没办法改主目录,而此主目录空间太小, 唯有安装TOMCAT之后进行更改... 参考文档: 工作中,由于Jenkins默认的主目录空间太小,导致需要将Jenkins默认的主 ...

  4. Hibernate 注解时 hibernate.hbm.xml的配置方法 以及与SSH整合里的配置方式

    ①纯Hibernate开发: 当你在Bean中写入注解后,需要告诉hibernate哪些类使用了注解. 方法是在hibernate.hbm.xml文件中配置 <!DOCTYPE hibernat ...

  5. java.lang.UnsupportedClassVersionError(java项目版本一致问题)

    报此错误,一般都是由于在myeclipse中的java项目是用高版本(jdk1.6之后)的jdk进行编译后生成的class文件,却要运行在低版本的jdk虚拟机上,导致这个错误 解决办法: 在myecl ...

  6. 在使用Ibatis查询数据返回时,报如下错误:java ibatis The error happened while setting a property on the result object

    问题: 在使用Ibatis查询数据返回时,报如下错误: [com.show.add.proxy.SqlMapClientTemplateProxy]com.ibatis.common.jdbc.exc ...

  7. Mozilla研究—深入理解mozilla所需的背景知识

    mozilla是一个以浏览器为中心的软件平台,它在我们平台中占有重要地位.我们用它来实现WEB浏览器.WAP浏览器.邮件系统.电子书和帮助阅读器等应用程序.为此,我最近花了不少时间去阅读mozilla ...

  8. 【Xamarin开发 Android 系列 4】 Android 基础知识

    原文:[Xamarin开发 Android 系列 4] Android 基础知识 什么是Android? Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Li ...

  9. Flatten Binary Tree to Linked List (LeetCode #114 Medium)(LintCode #453 Easy)

    114. Flatten Binary Tree to Linked List (Medium) 453. Flatten Binary Tree to Linked List (Easy) 解法1: ...

  10. 【Node】SuperAgent

    What is the current mechanism to construct a query string with SuperAgent?http://stackoverflow.com/q ...