Android蓝牙开发入坑指南

BLE简述

蓝牙是一套非常庞大复杂的协议栈,通俗的说就是一组应用于无线系统通信的约定,各个厂家根据这个约定生产出了各种蓝牙设备。由于蓝牙协议栈非常的庞大,很多厂商并不会完全实现蓝牙协议栈的所有功能。Android 4.3以后蓝牙开发一般都是基于低功耗蓝牙BLE4.0,BLE协议是蓝牙协议的子集。

BLE协议结构

上图是BLE协议结构,还是挺复杂的,Android开发人员可能只对GATT这个词有点印象,Android Framework帮我们屏蔽了上述大部分协议细节。Android的bluetooth包提供了BluetoothGattCallback类用来处理蓝牙连接,大致的过程是:

  1. 扫描蓝牙
  2. connectGatt发起连接
  3. 连接成功,扫描服务(Service)
  4. 读取属性(Characteristic)和描述信息(Description)
    具体的程序实现网上教程很多,这里不作介绍了,Service、Attribute、Description之间的关系见下图:
Service、Attribute、Description关系

蓝牙模块理论上说可以有许多Profile,不过大多数蓝牙模块就一个;Profile也可以包含很多Service(一般就一个),Service可以包含很多Characteristic(一般不止一个),有的蓝牙包含一个读Characteristic,一个写Characteristic,有的蓝牙读写共用一个Characteristic,Characteristic内部包含一个字节数组Value[],对于读写Characteristic来说Value[]就是用于收发的数据。Android Ble sdk调用比较麻烦,回调太多了,主要原因就在这里,蓝牙协议层级实在太多了。

BLE开发注意点

Android BLE开发过程中遇到的许多问题,严格来说并不都是Android本身的问题,很多问题来自作为通信目标的蓝牙模块,这些问题都需要开发人员注意:

信号干扰

蓝牙和WIFI都具有在2.4GHz信道通信的能力,某些Android设备蓝牙与Wifi信号会冲突,干扰特别严重,具体表现为蓝牙连接成功后收发数据时丢包和超时。这个问题如果出现了,几乎没有什么解决方案,只能在上层应用做好容错处理。

蓝牙初始化崩溃

这个问题存在于Android4.*的设备,蓝牙扫描设备后会往本地保存扫描记录,但是这个记录有上限,大概是500条,也就是说有搜索过500个不同的蓝牙设备后,手机再调用蓝牙扫描就会崩溃,系统设置里蓝牙扫描也会崩。这个问题影响不大,因为正常用户很难遇到,而且升级到Android 5.0以上就不会出现了。

连接间隔

基本上绝大多数Android蓝牙问题都是因为连接间隔导致的,那么连接间隔是什么呢?

蓝牙通信是基于电磁波的全双工通信,蓝牙通信的双方实际就是在不停的发出广播信号。广播消息意味着所有的设备都能收到消息,那么怎么确认每个消息是谁发给谁的呢?所以蓝牙通信前要先建立蓝牙连接,建立蓝牙连接简单理解的话,其实就是双方协商一致,以同一的步调收发数据,这个收发信号的间隔时间称为连接间隔。IOS蓝牙的连接间隔是20ms,直观的感受就是苹果蓝牙传输比较快;而Android蓝牙的连接时隔各厂商都不一样,有40ms、50ms、70ms等等,都比IOS要大一些。还有非常其怪的:华为2018年以后生产的很多手机型号,正常蓝牙通信时是40ms,但如果同时手机正在进行视频聊天,蓝牙连接间隔就会立即增加到70ms。

蓝牙模块每个连接间隔内收发的数据包有效载荷最大是20字节,写数据时如果往Characteristic里写数据20个字节,多余的数据会丢弃。假设连接间隔是40ms,那么蓝牙模块传输速率就是1000/40*20=500B/s,实在太慢了,BLE协议不适合收发大量数据。

连接间隔本来是一个非常底层的通信概念,Android开发时无法修改连接间隔。按理说开发APP应该不用关心连接间隔才对,就好像往磁盘上保存文件不用关心磁盘的转速一样,但是通信出错排查问题排查到这儿了,我们又不能不重视,这就有点像路由器的MTU一样,有时还真会导致服务器BUG。

连接间隔导致的问题一般都是效率问题,收发数据量太大,数据还没传完就超时了,连接间隔是系统控制的,无法修改,所以这个问题没有什么解决方案,只能在软件设计上做好容错处理,给数据传输留足时间。

连接间隔还会导致一些其怪的丢包问题,这种问题很难排查,好在有蓝牙协议分析仪可以去监听蓝牙信号,不过监听出来了,也没什么解决办法,如果是自研硬件的话,只能在硬件上下点功夫,Android上没有可修改的余地。

BLE与GPS

严格来说BLE与GPS真是一点关系都没有,但是Android很出人意料地将这俩联系在了一起,扫描蓝牙设备必须要申请定位权限!硬说的话,可能是因为蓝牙扫描能够获取信号强度,有了信号强度就可以推算距离,间接的就实现了定位吧!Android Framework其实也提供了不需要定位权限的扫描方法,其实就是非BLE的普通蓝牙扫描,但是这样无法获取scanRecord,也就是说无法得到BLE硬件的service uuid以及广播出来的数据,只能得到目标设备名字,几乎没法用。

另外,申请定位权限了并不表示就一定能扫描蓝牙了,有的Android设备必须要打开GPS定位的开关,否则就是扫描不出来,让人摸不着头脑。有时候Logcat里都系统日志已经打出来蓝牙扫描记录了,但是就是不触发LeScanCallback的回调,这种现象经常出现在vivo手机上。

配对问题

蓝牙协议提供了配对机制,其实就是让蓝牙记住目标设备,下次连接免去了扫描的步骤。其实扫描和配对都不是必须的,只要知道蓝牙设备的MAC地址,就可以直接发起蓝牙连接了(IOS有所差别,只能得到UUID,无法得到MAC地址)。但可能是出于安全考虑,配对之后的设备,蓝牙建立连接时会发起加密申请,询问目标设备是否支持加密通信,哪果目标设备不支持加密又不知道怎么应答,那连接就挂掉了,自研蓝牙设备时需要注意一下。

蓝牙开关问题

Android可以通过程序开启、关闭蓝牙,但是开启蓝牙需要动态权限申请,这倒是小事,交互设计时给个对话框和用户说一下就好了。开启蓝牙的操作即时返回结果的,而开启蓝牙是需要时间的,异步处理,大概几十毫秒,所以enable()后立即扫描蓝牙往往什么也搜不到。这个注意一下就好了,代码里加个延时不费事。一个特别要注意的事情,蓝牙enable()和disable()切记不能频繁操作,否则手机蓝牙会出现一现难琢磨的现象,甚至会被搞死机…而且实践发现,代码里enable()和在蓝牙设置里手动开启蓝牙是不一样的,有的时候enable()后蓝牙死活连不上,但是在系统设置里重新关闭、开启蓝牙就正常了。总之enable()要谨慎使用,有的手机(三星)特娇贵,蓝牙死机了重启手机都不好使。

Android与IOS对比

IOS蓝牙比Android蓝牙要稳定的多,毕竟型号单一嘛。在开发层面,IOS蓝牙不会显示设备MAC地址,其实对用户来说一般不会有查看蓝牙MAC地址的需求。蓝牙性能上,除了传输效率高,IOS蓝牙建立连接也比Android顺畅得多,尤其是蓝牙模块Characteristic很多的时候Android连接时discoverServices()会很慢。

企业采购蓝牙模块千万不能只用iphone做验证,IOS蓝牙实在比Android好太多。IOS上调试蓝牙可以用非常著名的LightBlue,体验非常棒;相应的Android上可以用nRF-Connect,体验差点儿,不过该有的功能都有的。

总结

个人实践来看,Android蓝牙模块稳定性并不高,和4G、wifi模块相比差很远,这其实是用户需求决定的,手机蓝牙确实很少使用,因而手机厂商对蓝牙模块的重视程度也不高,我们多次发现即使同一型号的手机,蓝牙性能也会天差地别,有的连接很稳定,有的丢包特别严重。我们猜测可能手机代工不一样,或者蓝牙模块不是采购自同一供应商。

蓝牙协议之所以被很多厂商所接受,就是因其功能很完善,实现灵活性很高,蓝牙模块只要实现蓝牙协议规定的功能即可,而代码如何写这个就是厂商自己的事情了,所以肯定会有兼容性能问题,兼容性问题总结下来就三个:扫描不到、连接不上、收不到数据,企业采购蓝牙模块一定要做好验收工作。

Anroid蓝牙给开发者的印象多是“不靠谱”,但是用于小规模、短时间数据传输还是非常方便的,比如用于共享单车开锁、智能手环等等。如果需要大规模数据传输的话还是wlan比较靠谱,比如智能摄像头、无人机都是采用wlan传输数据,有的智能硬件会把蓝牙与wifi模块相结合,比如通过蓝牙设置wlan密码接入wifi网络。蓝牙具有的功耗低、体积小的特点,这是很多无线通信方式无法批拟的,因此蓝牙在物联网领域还是大有可为的,开发者如何把充分利用手机蓝牙,我们还需要不断探索。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容