Android7.1(N) Ble 開發問題彙總一
最近又重操舊業,幫忙接了一些Android系統連線Ble外設的問題,這些問題比較棘手,如果不能修改Android系統原始碼,修復的可能性比較小。像三星這些大廠應該是有自己的團隊來解決這些問題,後面的問題彙總,僅供參考,希望能解決各位遇到的問題:
問題一:.Android系統啟動BLE掃描,預設掃描時間是30分鐘。
通常情況下,手機App的開發,不需要在後臺執行掃描外設,通常會把掃描的啟動和結束放到主介面裡,如果退出主介面就會停止掃描,但是如果你在你的app里加入了一個服務,且想讓app一直掃描,那麼你的掃描時間最多是30分鐘。為什麼呢?
第230行到第236中做了一個操作,即在啟動掃描的時候,同時啟動了一個Delay 30min的handle message,當30min時間到的時候會stop scan。所以如果你發現ble掃描30min就停止了,不要奇怪,因為是有人故意設定的,目的當時為了省功耗。
問題二:執行disconnect斷開外設連線,但是1s內又返回onConnected訊息,自動連線成功上外設。會讓開發者覺得disconnect不成功。
要想解決的這個問題,首先要清楚這個是什麼原因導致的。Android bluedroid機制裡有一個設定,就是隻要真正沒有app連線ble了才會斷開連線,超時時間是1s。
552#define GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP 1 /* start a idle timer for this duration 553 when no application need to use the link */
把這個define改成0,你會發現再執行disconnect會立即斷開連線,不會再在1s內收到onConnected回撥。這個問題的修復就不再是App工程師可以解決的問題,必須要系統工程師去修改bluedroid的原始碼才可以解決。
問題三:bluetoothGatt類的connect連線有時候連線比較慢的修復方式
今天再講最後一個問題,關於重連時間有點長甚至連線不上的問題。
大部分搞Ble的App工程師,從來不敢用bluetoothGatt類裡的connect方法,為什麼呢?因為從註釋裡只看到了重連外設,但是不知道該怎麼用,什麼時候用,出了問題怎麼解決。
在這裡我給大家深入解析一下這個方法:這個方法是谷歌提供給大家進行重連方法,當然使用的前提就是不要執行close()方法,不能釋放bluetoothGatt物件,現在大部分App工程師每次連線都會用BluetoothDevice類的connectGatt方法,收到onDisconnect回撥後,執行close釋放BlueotothGatt資源,不然你會發現conn_id會一直遞增,遞增幾個之後就連線不上了,所以很多同事就會讓你釋放BluetoothGatt類,執行close,這裡一定要等著收到onDisconnect之後再執行close方法,不然你會收不到onDisconnect回撥。
講了大家的通用做法,那麼BluetoothGatt的connect能不能用嗎?如果外設通常只連線一個,且不會經常改變的情況下,這個connect方法還是推薦使用的,為什麼呢?因為conn_id不會遞增,資源也不會釋放,在前臺執行時會連線比較快,且不會出錯。但是呢,有時候發現執行了connect方法,很長時間都沒有收到onConnect回撥。那這種情況下是為什麼呢?因為connect方法是一種後臺的連線方法,也就是說isDirect的引數預設是false的。可能有些人不知道isDirect是什麼,在大家使用conncectGatt的時候,會把autoConnect的引數設定成false,來關閉後臺連線,但是大家不知道的是,你在設定這個值的時候,系統會把isDirect的值設定成true,也就說autoConnect和isDirect是一對相反的操作。你想要自動連線,那麼autoConnect就會是true,相對應isDirect就是false。所以大家會用connectGatt設定autoConnect為false來提高連線效率,也就是把isDirect引數設定成了true。
所以這個也要在系統裡改一下。
700 public boolean connect() { 701 try { 702 mService.clientConnect(mClientIf, mDevice.getAddress(), 703 false, mTransport); // autoConnect is inverse of "isDirect" 704 return true; 705 } catch (RemoteException e) { 706 Log.e(TAG,"",e); 707 return false; 708 } 709 }
379 public void clientConnect(int clientIf, String address, boolean isDirect, int transport) { 380 GattService service = getService(); 381 if (service == null) return; 382 service.clientConnect(clientIf, address, isDirect, transport); 383 }
在這裡,就是Framework API通過binder呼叫的地方,當然framework的connect傳了一個false給bluetooth service。也就說isDirect為false。在這裡你可以在這裡強制給idDirect複製成true,就不會再出現回撥很慢,甚至沒有回到的情況了。
今天就更新這些,後續會繼續更新,歡迎關注。