Android藍牙4.0 BLE開發坑總結

  1. onServicesDiscovered 回調裏不能直接執行 write /readDataFromCharacteristic() 或者 enableNotificationOfCharacteristic之類的,而要放到主線程裏執行,如 handler.post( … );

  2. 如果發現連接上了,service也discover到了,但是始終不能觸發onCharacteristicChanged的,一定要查找如下2個重要原因:
    1). 一定要gatt.setCharacteristicNotification(characteristic, enable);
    2). 如果設置了1).卻還是發現沒有觸發,這個時候比較坑爹了,加上對此Characteristic的descriptor做indication Enable就應該可以了;

for(BluetoothGattDescriptor dp:characteristic().getDescriptors()) {
dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt().writeDescriptor(dp);
}

3.. 不同的機型的discoverService到onServiceDiscovered之間的耗時長短不一,這會導致一個問題:如果藍牙硬件設備支持離線傳輸,即有記憶功能,連接上之後多久發送之前的數據的問題。如果連接之上立即發送,那麼手機端的onServiceDiscovered尚未觸發,這樣Characteristic的值就獲取不了(因爲你的service,Characteristic都尚未初始化好),從而導致失敗。

解決的辦法有3個:
1)建立一套ACK機制,藍牙硬件設備不斷的廣播,直到所有的數據都收到返回的ACK確認纔不再廣播即可。
2)更好的辦法是,當手機端onServiceDiscovered觸發後,並且service,Characteristic都初始化好後,發送指令給藍牙硬件設備(即writeCharacteristic)表示手機端已經準備好,可以發送數據給我了,藍牙硬件設備收到後再發送數據,這樣能很好的保證數據不丟失。
3) 最好的辦法是1)和 2)的結合,即發送準備好的指令,然後讓智能硬件發送數據,然後在接收數據的過程中,使用ACK機制確保數據沒有任何丟失。

4.. Read/Write Characteristic/Descriptor 等都是異步的,即立即返回,等待回調。因此如果Android手機底層自身如果沒有做請求的同步順序執行的話,那麼當有很多請求幾乎同時進行時,回調順序是無法保證的。此時就造成錯誤,這也會導致很多藍牙4.0不能兼容某些Android的原因,因此需要自己提供一套同步機制,如RequestQueue,來保證request&response 一個接一個高效有序的進行,即下一個request必須等到上一個request的response返回之後再執行。

5.. Read/Write Characteristic/Descriptor/RemoteRssi(),一般在不同的線程中回調。(除了onDescriptorWrite返回的線程與寫入線程爲同一個線程???)

BluetoothDevice.conncectGatt(),
BluetoothGatt.connect(),
BluetoothGatt.disconnect(),
BluetoothGatt.discoverServices()
最好都在主線程,否則會遇到很多意想不到的麻煩。

6.. BLE的特徵一次讀寫最大長度20字節。

7.. Android手機會對連接過的BLE設備的Services進行緩存,若設備升級後Services等有改動,則程序會出現通訊失敗。此時就得刷新緩存,反射調用BluetoothGatt類總的refresh()方法。

8.. startLeScan(UUID[], LeScanCallback)在Android 4.4及以下手機中似乎只支持16位的短UUID,不支持128位。

9.. connectGatt() 在某些三星手機上只能在UI線程調用。

10.. Android L 新API掃描設備換爲 startScan(List, ScanSettings, ScanCallback)。

11.. Android M 必須擁有定位權限才能掃描BLE設備。

12.. 一個主設備(例如Android手機)可以同時連接多個從設備(一般爲6個,例如智能硬件。超過就連接不上了),一個從設備只能被一個主設備連接,一旦從設備連接上主設備,就停止廣播,斷開連接則繼續廣播。在任何時刻都只能最多一個設備在嘗試建立連接。如果同時對多個藍牙設備發起建立Gatt連接請求。如果前面的設備連接失敗了,則後面的設備請求會被永遠阻塞住,不會有任何連接回調。所以建議:如果要對多個設備發起連接請求,最好是一個接一個的順序同步請求管理。

13.. 任何出錯,超時,用完就馬上調用Gatt.disconnect(), Gatt.close()。

14.. 從bindService 到 onServiceConnected 這個回調花費時間較長, onServiceConnected 這個回調很可能在 MainActivity onResume之後才執行, 所以不要指望onResume裏去執行掃描,因爲此時serviceConnected 回調都尚未執行

15.. getBtAdapter().enable()是異步,立即返回,但從 off 到 on 的過程需要一個時間所以只能監聽系統broadcast發出的intent裏的state

16.. onCharacteristicWrite … 等等是指本機寫數據指令已經成功發送出去,並且智能硬件已經處理完迴應回來了,另外,當智能硬件端要求發送的指令有順序的話,那麼這邊不能發送速度過快,即不能在onCharacteristicWrite裏立即發送下一條指令。例如OAD/OTA等等,字節必須嚴格按照image的字節順序發送出去。
17.. 在writeCharacteristic時,若速度過快(例如在OAD時),會發現發送出去的數據有可能不是你自己真正發出去的,在onCharacteristicWrite裏打印出可以確定。
18.. App端的關於同一個UUID的2個指令不能同時發出去,這樣會導致硬件端無法辨識,所以需要串行發送,即等其中一個發送回調成功之後,再進行下一個。

19.. 多次掃描藍牙,在華爲榮耀,魅族M3 NOTE 中有的機型,會發現多次斷開–掃描–斷開–掃描… 會掃描不到設備,此時需要在斷開連接後,不能立即掃描,而是要先停止掃描後,過2秒再掃描才能掃描到設備。

20.. 掃描儘量不要放在主線程進行,可以放入子線程裏。不然有些機型會出現 do too many work in main thread.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章