簡介
自從Android-BLE庫開源了一段時間以來枪孩,越來越多的小伙伴問到了各種各樣的關(guān)于BLE的奇怪問題茁裙,在這里我想跟大家分享一下本人對于Android BLE藍牙的一些看法和解決方式咪奖,避免剛接觸的小伙伴再次踩坑冷守。
題外話
很多人曾問過我這個問題,為什么其他手機都沒什么問題餐茵,就華為的一些手機老是連接不穩(wěn)定炬转,經(jīng)常連接的很慢辆苔,而且連接上還經(jīng)常斷開。的確扼劈,在這里強調(diào)一下華為的一部分手機確實很容易出現(xiàn)這種問題驻啤,有時候軟件、硬件都搞不定荐吵,而且經(jīng)常性收到客戶投訴關(guān)于華為手機連接穩(wěn)定性問題骑冗,這個的確沒有完全解決的辦法,只能靠App和硬件的優(yōu)化先煎,并不是想甩鍋給華為贼涩,咱也不敢問到底是什么原因,而且我們公司專門針對各個Android版本的手機做過測試薯蝎,包括藍牙傳輸速率的測試遥倦,最后發(fā)現(xiàn)華為P20的速度竟然跟小米8的速度差了好幾倍,按理說P20手機也不便宜啊良风,為什么手機藍牙芯片不能做的再好一點呢谊迄?
問題集錦
一、掃描問題
1烟央、掃描不到設(shè)備
先確定下列幾項是否滿足:
1统诺、藍牙是否打開
2、藍牙相關(guān)權(quán)限是否授權(quán)(6.0以上位置權(quán)限)
3疑俭、7.0以上手機很多需要手動打開GPS
2粮呢、有時候剛開始掃描還正常,過段時間掃描不到設(shè)備钞艇?
原因:
出現(xiàn)這個問題的很多是Android7.0以上手機啄寡,為什么呢?
因為Google為了防止Android7中的BLE掃描濫用哩照,從而做了一些限制挺物,即不要在30s內(nèi)對藍牙掃描
重復開啟-關(guān)閉超過5次。
建議:
設(shè)置掃描周期>6s, 用戶點擊掃描后不要重復進行掃描飘弧,可以做一個是否正在掃描的標志位识藤,如果
正在掃描就不做重復掃描動作了。
3次伶、為什么有些手機退到后臺掃描不到設(shè)備
Android8.0以上退到后臺息屏后痴昧,為了保證省電等原因,如果不設(shè)置ScanFilters的話是默認掃不到設(shè)備的冠王,
所以解決辦法就是設(shè)置如下:
mScannerSetting = new ScanSettings.Builder()
//退到后臺時設(shè)置掃描模式為低功耗
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
mFilters.add(new ScanFilter.Builder()
//過濾掃描藍牙設(shè)備的主服務(wù)
.setServiceUuid(ParcelUuid.fromString("0000ffff-0000-1000-8000-00805f9bfffb"))
.build());
mScanner.startScan(mFilters, mScannerSetting, mScannerCallback);
息屏狀態(tài)下赶撰,藍牙掃描日志,因為掃描周期是12s柱彻,所以打印的時間戳間隔是12s豪娜,這里的日志為系統(tǒng)日志。
翻譯:
啟動藍牙掃描绒疗。掃描結(jié)果將通過回調(diào)傳遞侵歇。對于未經(jīng)過濾的掃描,掃描是停止在屏幕上關(guān)閉吓蘑,以節(jié)省
電力惕虑。再次打開屏幕時,將恢復掃描磨镶。為了避免這種情況溃蔫,請使用適當?shù)膾呙柽^濾器進行文件掃描。
二琳猫、連接問題
1伟叛、為什么同時多個設(shè)備連接時經(jīng)常連接不成功?
可能原因:
在使用 BluetoothDevice.connectGatt() 或者 BluetoothGatt.connect() 等建立 BluetoothGatt
連接的時候脐嫂,在任何時刻都只能最多一個設(shè)備在嘗試建立連接统刮。如果同時對多個藍牙設(shè)備發(fā)起建立 Gatt
連接請求紊遵。如果前面的設(shè)備連接失敗了,后面的設(shè)備請求會被永遠阻塞住侥蒙,不會有任何連接回調(diào)暗膜。
建議:
如果要對多個設(shè)備發(fā)起連接請求,最好建立一個請求隊列鞭衩,前一個設(shè)備請求建立連接学搜,后面請求在隊列中等待
。如果連接成功了论衍,就處理下一個連接請求瑞佩。如果連接失敗了(例如出錯,或者連接超時失斉魈ā)炬丸,就馬上調(diào)用
BluetoothGatt.disconnect()/close()來釋放建立連接請求,然后處理下一個設(shè)備連接請求捂人。
2御雕、為什么有時候連接成功了,但是發(fā)現(xiàn)不了服務(wù)及特征值滥搭,進而影響數(shù)據(jù)的接收和發(fā)送酸纲。
連接成功后,會進行BluetoothGatt.discoverServices()去發(fā)現(xiàn)服務(wù)瑟匆,進而設(shè)置特征值等闽坡,因為該方法是在主
線程中執(zhí)行的,所以為了連接過程的可靠性愁溜,建議不要在該過程中疾嗅,在主線程中不要處理太多的操作(尤其是頻
繁繪制操作)。
3冕象、為什么連接成功后代承,過不一會又斷開了熬尺?
這個問題其實并不主要是客戶端的問題旁振,所以不要一味的在代碼中找問題了,建議與硬件溝通钦睡,讓其進行優(yōu)化
墓律,如可以調(diào)整設(shè)備的連接參數(shù)(ConnectionInterval(連接間隔)膀估、SlaveLatency(從設(shè)備延遲或者從設(shè)備時
延)、SupervisionTimeout(超時時間或者監(jiān)控超時))耻讽,這三個參數(shù)是低功耗藍牙中十分重要的連接參數(shù)察纯,
一起決定了BLE的功耗,一般硬件設(shè)備會在APP連接成功時主動去更新一下這三個參數(shù),以保證不同手機的差異
性得到一致饼记,但是APP端是沒辦法控制這三個參數(shù)的香伴。
4、最大連接數(shù)問題
標準答案是7個具则,為什么是7個瞒窒,這個我們可以從如下圖所示的底層藍牙源碼中找到依據(jù)。
5乡洼、連接api的使用問題
發(fā)起藍牙Gatt連接 BluetoothDevice.connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback),這里有一個參數(shù)autoConnect匕坯,如果為 true
的話束昵,系統(tǒng)就會發(fā)起一個后臺連接,等到系統(tǒng)發(fā)現(xiàn)了一個設(shè)備葛峻,就會自動連上锹雏,通常這個過程是非常慢的。為
false 的話术奖,就會直接連接礁遵,通常會比較快。同樣采记,BluetoothGatt.connect()只能發(fā)起一個后臺連接佣耐,不是直
接連接,所以連接時設(shè)置autoConnect參數(shù)設(shè)置為false,如果想實現(xiàn)重連功能的話唧龄,自己去手動實現(xiàn)吧兼砖,實在不
想手動寫,那就用Android-BLE庫吧既棺,你想要的基本都有讽挟。
6、為什么連接總是報133丸冕、19之類的非0異常
原因:可能由于首次連接藍牙后沒有釋放掉gatt資源導致的藍牙協(xié)議棧異常耽梅,從而出現(xiàn)133或257
19等值不為0:由于協(xié)議棧,連接建立失敗
建議:在onConnectionStateChange()回調(diào)中判斷胖烛,若state非0(連接斷開)眼姐,調(diào)用gatt.close(),手動釋放掉
gatt相關(guān)資源
三洪己、數(shù)據(jù)發(fā)送問題
1妥凳、為什么連接成功了,發(fā)送數(shù)據(jù)總是失敶鸩丁逝钥?
原因:
1、首先確定主服務(wù)是否正確,再看設(shè)置的讀艘款、寫特征值是否正確
2持际、因為BLE發(fā)現(xiàn)服務(wù)和設(shè)置特征、通知等是需要耗時的哗咆,所以你并不能連接成功后立馬發(fā)送數(shù)據(jù)蜘欲,可以等到在
onDescriptorWrite()回調(diào)時,或者手動延遲一段時間再去做發(fā)送操作晌柬。
2姥份、為什么要分包發(fā)送
BLE4.0藍牙發(fā)送數(shù)據(jù),單次最大傳輸20個byte,如果是一般的協(xié)議命令年碘,如:開關(guān)燈澈歉、前進左右等等,是不需要
分包的屿衅,如果是需要發(fā)送如:圖片埃难、BIN文檔、音樂等大數(shù)據(jù)量的文件涤久,則必須進行分包發(fā)送涡尘,BLE庫中已經(jīng)提
供了發(fā)送大數(shù)據(jù)包的接口,需要的小伙伴可以去下載DEMO查看用法响迂。