Android BLE裝置藍芽通訊架構BluetoothKit

來源:互聯網
上載者:User

標籤:uid   pos   log   tor   com   回調   anr   服務   tle   

BluetoothKit是一款功能強大的Android藍芽通訊架構,支援低功耗藍牙裝置的串連通訊、藍芽廣播掃描及Beacon解析。

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

對於剛接觸Android藍芽開發的初學者來說,會經常遇到一些奇怪的坑,我也是一路走過來的,將我遇到的一些坑總結了一下,這些坑在這個項目中都修複了,所以大家不必再費時費力去重複踩一遍。這個項目目前正在不斷更新,有什麼更好的建議大家可以隨時提出來。

藍芽掃描相關的坑

一、startDiscovery在大多數手機上是可以同時發現經典藍芽和Ble的,但是startDiscovery的回調無法返回Ble的廣播,所以無法通過廣播識別裝置,且startDiscovery掃描Ble的效率比StartLeScan低很多。所以在實際應用中,還是StartDiscovery和StartLeScan分開掃,前者掃經典藍芽,後者掃低功耗藍芽。

二、startLeScan() 的時候,在onLeScan() 中不能做耗時操作,特別是周圍的BLE裝置多的時候,容易導致底層堵塞。如果有耗時操作請丟到子線程中去處理。

三、有的手機會過濾裝置廣播,一次掃描過程中只發一次request,如果沒有收到response就再也收不到該裝置廣播回調了,解決的辦法是多掃幾次。

藍芽串連相關的坑

一、對藍牙裝置的操作不能並行,只能串列,即每次都要在收到上一個操作的回調後才能繼續下一個操作。但是中斷連線例外,中斷連線要馬上closeGatt,不用等任務隊列中的其他動作了。而且要給所有正在執行或者準備執行的任務都cancel。

二、有時候藍芽協議棧出現異常可能收不到回調,所以我們要對每個操作做逾時檢查,否則後面的所有操作都被阻塞了。

三、對於逾時的任務,最好closeGatt,下次重新串連的時候重開一個gatt。

四、藍芽串連可能不穩定,最好支援失敗自動重試機制,尤其是串連和探索服務,因為80%的問題都發生在建立串連和探索服務的時候,而且這一塊也是最耗時的。

五、當串連建立後,可以由裝置端發起更改串連間隔,這樣能加快後續探索服務以及資料讀寫的速度。有的手機discover service很慢,原因是connect interval太大了,有的手機會主動向裝置發起更改connect interval,而有的手機卻不會。這樣的話connect interval相差就會很大,實踐中發現有的手機是7ms,有的手機是預設的50ms,所以發現service都要8s,甚至20s的都很尋常,這對使用者來說是無法忍受的。所以比較好的辦法是裝置主動發起更改connect interval

六、同一個裝置的所有操作最好都放在同一個線程串列執行,最好不要放在UI線程,雖然這些操作都是非同步,理論上來說不會耗時,但是由於涉及到跨進程,還是有可能出現ANR。另外不建議每個裝置都開一個線程,裝置多了會費記憶體也會降低效能。較好的做法是開一個線程,所有裝置的操作都在該線程中發起,雖然佔用同一個線程,但是每個裝置各自維護自己的任務隊列。

七、藍芽操作都是非同步,回調通常都在binder線程裡執行,因為這是跨進程回調回來的。一定要注意到這一點,否則會出現一些奇怪的問題。比如writeCharacter在背景工作執行緒,但是onCharacterWrite是在binder線程,回調裡如果涉及到任務隊列的調度一定要post回背景工作執行緒中處理,否則會出現多線程造成的資料不一致問題。

八、接著第七條,在回調中post回背景工作執行緒處理時要注意不要帶控制代碼,而是要帶資料。比如對於onCharacteristicWrite,不要帶BluetoothGattCharacteristic,而是要帶其中的value。否則會漏掉一些資料,且最後可能收到一組重複的資料。同樣的問題在notify上也有。

九、當裝置韌體升級後,profile可能發生了變化,然而下次discover service的時候還是返回的舊的緩衝,這樣讀寫character可能會失敗。解決辦法是韌體升級後,下次串連時重新整理一下該裝置的緩衝。當然,重啟藍芽也會重新整理緩衝,不過會影響到所有裝置。另外有時候discoverService服務發現的不全,或者根本發現不了服務,也可以考慮清除一下緩衝。

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

十一、service不要緩衝,雖然uuid什麼的可能都沒變,但是這些service都會和gatt關聯的,如果gatt變了,那service就報廢了,對這些service和character做任何讀寫操作都會出錯。所以建議每次串連上時都去discover service,不要緩衝。

十二、韌體升級通常是寫裝置,為加快寫速度,可以在write character時指定no response標誌,實踐發現速度可以提升2~3倍。不過要注意的是即便帶了no response標誌,也不代表這種寫操作是沒有回調的,我們仍然要遵循收到上一次寫回調後才能進行下一次寫操作。提升寫速度的手段還有更改MTU和更改串連間隔,不過更改MTU硬體不一定支援,得嘗試幾次。

十三、寫的時候不要指定writeType,不指定writeType不代表writeType就是WRITE_TYPE_DEFAULT,事實上系統會自動根據property來決定writeType,如果帶PROPERTY_WRITE_NO_RESPONSE屬性,則會自動選擇WRITE_TYPE_NO_RESPONSE,否則才會選擇WRITE_TYPE_DEFAULT。

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

十五、裝置的gatt在不用時要及時關閉,系統支援的串連控制代碼數是有限的,當達到上限後無法再建立新的串連了。

十六、當串連斷開後要調closeGatt釋放資源,不用調disconnect,也不要下次複用之前的gatt來reconnect,因為有的手機上重連可能會存在問題,比如重連後死活發現不了service。這種情況下,最好只要中斷連線就close gatt,下次串連時開啟全新的gatt,這樣就可以發現service了。

 

使用

使用起來非常簡單,添加一行依賴,然後建立一個全域單例BluetoothClient,詳細介面調用方法參考上面的連結。

1、在build.gradle中添加依賴

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

2、建立一個BluetoothClient,最好做成單例全域使用

BluetoothClient mClient = new BluetoothClient(context);
使用到的一些技術

**一、實現了一個 
完整的跨進程非同步任務隊列,支援任務逾時、出錯重試及防禦隊列溢出**

二、攔截並Hook系統層藍芽Binder,實現對所有藍牙裝置通訊的監控,當同時串連裝置數過多時會自動斷掉活躍度最低的裝置

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

四、屏蔽了介面非同步回調可能持有調用端Activity引用導致的記憶體泄露

五、利用動態代理自動將所有操作封閉在背景工作執行緒,所以整個架構無鎖

Android BLE裝置藍芽通訊架構BluetoothKit

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.