在Android 中蓝牙4.0开发有一定时间了,这个过程中由于公司对蓝牙的使用要求比较苛刻,即希望连接上千次都不希望影响之后的使用,这个目标想要适配到所有手机中还是有点艰难的,同时也在这里面踩坑踩的不要不要的,以下是在蓝牙开发中踩过的一部比较印象比较深刻的坑,希望对大家有所帮助。
对android 蓝牙刚接触的人建议看一 下这篇文章:https://race604.com/android-ble-in-action/
1.BluetoothGatt.disconnect() 之后不能要马上BluetoothGatt.close().建议在 BluetoothGattCallback中收到BluetoothGatt.STATE_DISCONNECTED时才BluetoothGatt.close()
理由:disconnect() 之后调用close()虽然大部分手机调用正常,但存在手机蓝牙连接实际没有断开!!!这个会造成蓝牙资源泄露的问题,甚至蓝牙假死。同时这个最好做一个超时机制来释放连接,避免存在BluetoothGattCallback没有回调的情况。(注:之前有遇到手机在极端情况下没有回调)
2.蓝牙api调用过程建议采用notify() 和 wait()
理由:蓝牙的api调用基本都是异步的,但整个过程都是按顺序来的(connect->discovertServices->write->read.....disconnect),尤其是Characteristic读写非常复杂的时候,一旦出错会让你非常奔溃,甚至会导致蓝牙假死问题!!!所以建议封装异步调用成为同步调用(即用notify和wait),来大幅度地减少出错的可能。
3.蓝牙 startScan 分了低版本(5.0之下)和高版本(5.0以上)的api,低版本中建议startLeScan不要传递uuid,高版本中建议不要用到onBatchScanResults的方式。
理由:存在少部分机型底层没有处理好,导致完全扫描不到任何数据。
4. Android 7.0 以上系统不要在短时间内调用多次 startScan
理由:Android 7.0系统限制在 30s内最多只能扫描5次,用完之后在30s内是扫不到任何蓝牙的。
5.BluetoothGatt.requestConnectionPriority() 方法慎用(建议做机型覆盖)
理由:该方法可以修改蓝牙的连接间隔,加快蓝牙的连接过程(connect 到 discoverServices),但是在比较旧的机型(类似华为)发现,在连续调用几次后,后面的蓝牙变得连接非常不稳定.
6.不要持续调用蓝牙扫描
理由:在部分机型持续一定时间扫描后会发现需要重启蓝牙才能恢复扫描,这个现象在魅族手机上有遇到过;很久之前遇到蓝牙进行重复的扫描,停止扫描两个操作,一定时间后在传说中的国民手机红米上会出现这个bug,而且还必须重启手机才能恢复蓝牙功能。
7.手机做为中心设备建立连接,但由外设断开蓝牙连接时容易导致外设一定时间内连接不上,所以建立最好不要由外设来进行断开连接。
理由:这个可能跟蓝牙的一个断开协议有关系,正常来讲中心设备只要收到外设的断开指令后还会回馈给外设一个“收到断开”的回复,外设收到断开回复流程才算完成。但假设中心设备没有回复时,外设会持续等待直到超时断开(一般是10s),意思就是从端设备需要至少10s后才能再次被连接上。(该情况在oppo手机上100%必现)
8.采用BluetoothManager.getConnectedDevices(int profile)来检查当前蓝牙连接的情况
理由:可以用来检测蓝牙资源有没有释放干净,因为避免繁琐的异步通信中容易出差。不过此法返回的连接数为空时,也不代表蓝牙的连接完全释放干净。
9.在小米mix2手机上,黑屏模式,service处于后台,蓝牙也没有调用,持续几分钟后,想调用蓝牙startScan方法,但无法扫描蓝牙或者扫描报异常,并且会有此日志--》 BluetoothLeScanner: start scan is blocked。
解决方法:
方案一:设置-》电量和性能 -》省电忧化 -》应用智能省电-》选择应用-》无限制
方案二:android 8.0 出了新的startScan方法,还可用于近场拉活进程(传送门),api描述见下图:
蓝牙广播踩到的坑
使用蓝牙广播可以用来做许多事情,市面上有类似Ibeacon的产品就是基于蓝牙广播类现的,但在android 中还是有很多坑的。
1.android 5.0 以上才支持广播这就算了,在5.0以上部分机器还不支持蓝牙广播,例如:亲儿子nexus 5,甚至华为有些到达7.0系统的手机还不支持。
2.存在缓在,许多手机会将上一次广播过的内容再次广播出来一下才广播正常内容
3.android 对比ios,普遍机型广播信号强度弱,广播间隔偏少
4.存在手机进行多次广播后,蓝牙会自动重启(oppo手机上有遇到此类问题)
5.手机端广播出来的蓝牙mac地址不是固定的,每广播一次,变化一次
6.AdvertiseSettings.Builder.setTimeout() 调用时注意!!!
理由:Oppo r11,三星 Galaxy On7 (android 7.0)等机型,调用BluetoothLeAdvertiser.startAdvertising() 偶尔返回 ADVERTISE_FAILED_ALREADY_STARTED,偿试多次返回ADVERTISE_FAILED_TOO_MANY_ADVERTISERS,这很明显存在蓝牙广播泄漏问题!!!!
解决方法:由于该现象只在7.0以上的机型出现,所以本人只针对7.0以上的机型做处理。去掉setTimeout()方法,改为用线程延时调用BluetoothLeAdvertiser.stopAdvertising()停止广播
以下是其它前辈的踩坑总结:
http://blog.csdn.net/qingtiantianqing/article/details/52459629?locationNum=13