Android7.1(N) Ble 開發問題彙總一

轉載請標明出處:https://blog.csdn.net/lansefeiyang08/article/details/82774977

最近又重操舊業,幫忙接了一些Android系統連接Ble外設的問題,這些問題比較棘手,如果不能修改Android系統源碼,修復的可能性比較小。像三星這些大廠應該是有自己的團隊來解決這些問題,後面的問題彙總,僅供參考,希望能解決各位遇到的問題:

問題一:.Android系統啓動BLE掃描,默認掃描時間是30分鐘。

通常情況下,手機App的開發,不需要在後臺運行掃描外設,通常會把掃描的啓動和結束放到主界面裏,如果退出主界面就會停止掃描,但是如果你在你的app里加入了一個服務,且想讓app一直掃描,那麼你的掃描時間最多是30分鐘。爲什麼呢?

因爲在系統源碼路徑/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/ScanManager.java中的 handleStartScan方法裏有這樣一個操作:

207        void handleStartScan(ScanClient client) {
208            Utils.enforceAdminPermission(mService);
209            logd("handling starting scan");
210
211            if (!isScanSupported(client)) {
212                Log.e(TAG, "Scan settings not supported");
213                return;
214            }
215
216            if (mRegularScanClients.contains(client) || mBatchClients.contains(client)) {
217                Log.e(TAG, "Scan already started");
218                return;
219            }
220            // Begin scan operations.
221            if (isBatchClient(client)) {
222                mBatchClients.add(client);
223                mScanNative.startBatchScan(client);
224            } else {
225                mRegularScanClients.add(client);
226                mScanNative.startRegularScan(client);
227                if (!mScanNative.isOpportunisticScanClient(client)) {
228                    mScanNative.configureRegularScanParams();
229
230                    if (!mScanNative.isExemptFromScanDowngrade(client)) {
231                        Message msg = mHandler.obtainMessage(MSG_SCAN_TIMEOUT);
232                        msg.obj = client;
233                        // Only one timeout message should exist at any time
234                        mHandler.sendMessageDelayed(msg, AppScanStats.SCAN_TIMEOUT_MS);
235                    }
236                }

237
238                // Update BatteryStats with this workload.
239                try {
240                    mBatteryStats.noteBleScanStarted(client.workSource);
241                } catch (RemoteException e) {
242                    /* ignore */
243                }
244            }
245        }

第230行到第236中做了一個操作,即在啓動掃描的時候,同時啓動了一個Delay 30min的handle message,當30min時間到的時候會stop scan。所以如果你發現ble掃描30min就停止了,不要奇怪,因爲是有人故意設置的,目的當時爲了省功耗。

問題二:執行disconnect斷開外設連接,但是1s內又返回onConnected消息,自動連接成功上外設。會讓開發者覺得disconnect不成功。

要想解決的這個問題,首先要清楚這個是什麼原因導致的。Android bluedroid機制裏有一個設置,就是隻要真正沒有app連接ble了纔會斷開連接,超時時間是1s。

因爲系統/system/bt/stack/include/gatt_api.h下有這樣一個定義:

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。

所以這個也要在系統裏改一下。

系統代碼路徑:/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java

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    }

系統路徑爲:/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java

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,就不會再出現回調很慢,甚至沒有回到的情況了。

今天就更新這些,後續會繼續更新,歡迎關注。

 

 

 

 

 

 

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