Android BLE設備藍牙通訊框架BluetoothKit

BluetoothKit是一款功能強大的Android藍牙通訊框架,支持低功耗藍牙設備的鏈接通訊、藍牙廣播掃描及Beacon解析。android

關於該項目的詳細文檔請關注:https://github.com/dingjikerbo/BluetoothKitgit

對於剛接觸Android藍牙開發的初學者來講,會常常遇到一些奇怪的坑,我也是一路走過來的,將我遇到的一些坑總結了一下,這些坑在這個項目中都修復了,因此你們沒必要再費時費力去重複踩一遍。這個項目目前正在不斷更新,有什麼更好的建議你們能夠隨時提出來。github

藍牙掃描相關的坑

1、startDiscovery在大多數手機上是能夠同時發現經典藍牙和Ble的,可是startDiscovery的回調沒法返回Ble的廣播,因此沒法經過廣播識別設備,且startDiscovery掃描Ble的效率比StartLeScan低不少。因此在實際應用中,仍是StartDiscovery和StartLeScan分開掃,前者掃經典藍牙,後者掃低功耗藍牙。緩存

2、startLeScan() 的時候,在onLeScan() 中不能作耗時操做,特別是周圍的BLE設備多的時候,容易致使底層堵塞。若是有耗時操做請丟到子線程中去處理。多線程

3、有的手機會過濾設備廣播,一次掃描過程當中只發一次request,若是沒有收到response就再也收不到該設備廣播回調了,解決的辦法是多掃幾回。框架

藍牙鏈接相關的坑

1、對藍牙設備的操做不能並行,只能串行,即每次都要在收到上一個操做的回調後才能繼續下一個操做。可是斷開鏈接例外,斷開鏈接要立刻closeGatt,不用等任務隊列中的其餘操做了。並且要給全部正在執行或者準備執行的任務都cancel。異步

2、有時候藍牙協議棧出現異常可能收不到回調,因此咱們要對每一個操做作超時檢查,不然後面的全部操做都被阻塞了。post

3、對於超時的任務,最好closeGatt,下次從新鏈接的時候重開一個gatt。性能

4、藍牙鏈接可能不穩定,最好支持失敗自動重試機制,尤爲是鏈接和發現服務,由於80%的問題都發生在創建鏈接和發現服務的時候,並且這一塊也是最耗時的。gradle

5、當鏈接創建後,能夠由設備端發起更改鏈接間隔,這樣能加快後續發現服務以及數據讀寫的速度。有的手機discover service很慢,緣由是connect interval太大了,有的手機會主動向設備發起更改connect interval,而有的手機卻不會。這樣的話connect interval相差就會很大,實踐中發現有的手機是7ms,有的手機是默認的50ms,因此發現service都要8s,甚至20s的都很尋常,這對用戶來講是沒法忍受的。因此比較好的辦法是設備主動發起更改connect interval

6、同一個設備的全部操做最好都放在同一個線程串行執行,最好不要放在UI線程,雖然這些操做都是異步的,理論上來講不會耗時,可是因爲涉及到跨進程,仍是有可能出現ANR。另外不建議每一個設備都開一個線程,設備多了會費內存也會下降性能。較好的作法是開一個線程,全部設備的操做都在該線程中發起,雖然佔用同一個線程,可是每一個設備各自維護本身的任務隊列。

7、藍牙操做都是異步的,回調一般都在binder線程裏執行,由於這是跨進程回調回來的。必定要注意到這一點,不然會出現一些奇怪的問題。好比writeCharacter在工做線程,可是onCharacterWrite是在binder線程,回調裏若是涉及到任務隊列的調度必定要post回工做線程中處理,不然會出現多線程形成的數據不一致問題。

8、接着第七條,在回調中post回工做線程處理時要注意不要帶句柄,而是要帶數據。好比對於onCharacteristicWrite,不要帶BluetoothGattCharacteristic,而是要帶其中的value。不然會漏掉一些數據,且最後可能收到一組重複的數據。一樣的問題在notify上也有。

9、當設備固件升級後,profile可能發生了變化,然而下次discover service的時候仍是返回的舊的緩存,這樣讀寫character可能會失敗。解決辦法是固件升級後,下次鏈接時刷新一下該設備的緩存。固然,重啓藍牙也會刷新緩存,不過會影響到全部設備。另外有時候discoverService服務發現的不全,或者根本發現不了服務,也能夠考慮清除一下緩存。

10、有的手機上discoverService可能會回調不止一次onServiceDiscover,這個要注意防護。

11、service不要緩存,雖然uuid什麼的可能都沒變,可是這些service都會和gatt關聯的,若是gatt變了,那service就報廢了,對這些service和character作任何讀寫操做都會出錯。因此建議每次鏈接上時都去discover service,不要緩存。

12、固件升級一般是寫設備,爲加快寫速度,能夠在write character時指定no response標誌,實踐發現速度能夠提高2~3倍。不過要注意的是即使帶了no response標誌,也不表明這種寫操做是沒有回調的,咱們仍然要遵循收到上一次寫回調後才能進行下一次寫操做。提高寫速度的手段還有更改MTU和更改鏈接間隔,不過更改MTU硬件不必定支持,得嘗試幾回。

十3、寫的時候不要指定writeType,不指定writeType不表明writeType就是WRITE_TYPE_DEFAULT,事實上系統會自動根據property來決定writeType,若是帶PROPERTY_WRITE_NO_RESPONSE屬性,則會自動選擇WRITE_TYPE_NO_RESPONSE,不然纔會選擇WRITE_TYPE_DEFAULT。

十4、打開/關閉character的notify,必須等收到onDescriptorWrite回調以後纔算結束,才能開始下一個任務。

十5、設備的gatt在不用時要及時關閉,系統支持的鏈接句柄數是有限的,當達到上限後沒法再創建新的鏈接了。

十6、當鏈接斷開後要調closeGatt釋放資源,不用調disconnect,也不要下次複用以前的gatt來reconnect,由於有的手機上重連可能會存在問題,好比重連後死活發現不了service。這種狀況下,最好只要斷開鏈接就close gatt,下次鏈接時打開全新的gatt,這樣就能夠發現service了。

 

使用

使用起來很是簡單,添加一行依賴,而後建立一個全局單例BluetoothClient,詳細接口調用方法參考上面的連接。

一、在build.gradle中添加依賴

compile 'com.inuker.bluetooth:library:1.3.8'

二、建立一個BluetoothClient,最好作成單例全局使用

BluetoothClient mClient = new BluetoothClient(context);

使用到的一些技術

**1、實現了一個 
完整的跨進程異步任務隊列,支持任務超時、出錯重試及防護隊列溢出**

2、攔截並Hook系統層藍牙Binder,實現對全部藍牙設備通訊的監控,當同時鏈接設備數過多時會自動斷掉活躍度最低的設備

3、整個框架封裝在一個service中,可靈活指定service所在進程。

4、屏蔽了接口異步回調可能持有調用端Activity引用致使的內存泄露

5、利用動態代理自動將全部操做封閉在工做線程,因此整個框架無鎖

相關文章
相關標籤/搜索