AndroidBLE開發過程中遇到的問題記錄
Android BLE 開發過程中遇到的問題記錄
1.斷開連線後出現133錯誤
在斷開連線之後再次連線經常會出現133錯誤,並且難以連線成功,處理方式如下:
首先在重連的時候先將Gatt快取進行清理:
public boolean refreshDeviceCache() { if (mBluetoothGatt != null) { try { BluetoothGatt localBlueToothGatt = mBluetoothGatt; Method localMethod = localBlueToothGatt.getClass().getMethod("refresh", new Class[0]); if (localMethod != null) { Boolean bool = ((Boolean) localMethod.invoke(localBlueToothGatt, new Object[0])).booleanValue(); return bool; } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e2) { e2.printStackTrace(); } catch (IllegalAccessException e3) { e3.printStackTrace(); } } return false; }
然後將Gatt連線進行close操作:
mBluetoothGatt.close(); mBluetoothGatt = null;
再次連線時,使用一個全新的Gatt物件進行連線操作,而且在連線之前再次確認Gatt連線是否已經釋放:
/** * 連線裝置Gatt * * @param device 裝置 */ private void connectDevice(final BluetoothDevice device) { if (mBluetoothAdapter == null) { Log.d(TAG, "connectDevice: BluetoothAdapter not initialized."); return; } if (!mBluetoothAdapter.isEnabled()) { Log.d(TAG, "connectDevice: BluetoothAdapter is disabled"); return; } if (device == null) { Log.d(TAG, "connectDevice: Unspecified device."); return; } //防止連接出現133錯誤, 不能發現Services if (mBluetoothGatt != null || getState() == State.Connecting) { Log.d(TAG, "connectDevice: closeGatt"); mBluetoothGatt.disconnect(); close(); } if (mBluetoothGatt != null && mBluetoothGatt.getDevice() != null && mBluetoothGatt.getDevice().equals(device)) { Log.d(TAG, "connectDevice: Trying to use an existing mBluetoothGatt for connection."); mBluetoothGatt.connect(); } else { Log.d(TAG, "connectDevice: Trying to create a new connection."); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mBluetoothGatt = device.connectGatt(MyApplication.getInstance(), false, mGattCallback, BluetoothDevice.TRANSPORT_LE); } else { mBluetoothGatt = device.connectGatt(MyApplication.getInstance(), false, mGattCallback); } } }
這種操作下來即使出現133,也能在多次嘗試重連之後連線成功。
其次,出現133也很有可能與硬體有關,筆者使用的硬體硬體在初期經常出現133錯誤,但硬體進行了調優之後出現的頻率大大降低了,所以並不是所有的問題都是Android裝置的錯。
2.互動時出現128錯誤
開發過程中命令互動的時候出現128錯誤,連線中止:
這個錯誤出現的原因是因為gatt命令互動並不能並行操作,一旦上一個命令還未反饋結束就再次傳送下一個命令就會出現128錯誤。
3.發現服務之後立即進行連線,部分機型無法成功
在開發過程中發現,建立連線過程中,發現服務之後如果立即書寫特徵值,可能出現部分機型無法成功連線的情況:
通過長期測試,目前將每一條特徵值的書寫進行了700ms的延遲,暫時可以支援絕大部分機型。
@Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); mBluetoothGatt = gatt; if (status == BluetoothGatt.GATT_SUCCESS) { Log.d(TAG, "onServicesDiscovered. status = " + status); //UUID serviceUuid = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); BluetoothGattService service = gatt.getService(mServiceUuid); if (BuildConfig.DEBUG) Log.d(TAG, "service.getUuid():" + service.getUuid()); if (service != null) { List characteristics = service.getCharacteristics(); for (int j = 0; j < characteristics.size(); j++) { final BluetoothGattCharacteristic characteristic = (BluetoothGattCharacteristic) characteristics.get(j); Log.d(TAG, "characteristic = " + characteristic.getUuid().toString()); Log.d(TAG, String.format("characteristic.properties = %X", characteristic.getProperties())); if ((characteristic.getProperties() & (BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristi gatt.setCharacteristicNotification(characteristic, true); sHandler.postDelayed(new Runnable() { @Override public void run() { try { BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(CLIENT_CHARAC if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0 descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } } catch (Exception e) { reScanDevice(); e.printStackTrace(); } } }, 700 * j); } } } } else { reScanDevice(); Log.d(TAG, "onServicesDiscovered. status = " + status); } }
4.BLE藍芽命令互動確保是有序序列的
由於BLE藍芽命令互動時序列的所以在開發過程中對此必須嚴格遵守,異常出現的並行命令極有可能造成各種問題,而且不容易定位bug,當然這部分可以使用第三方封裝好的庫來做。
5.各品牌手機省電策略引起的問題
華為: 非常嚴格,如果不開啟任何白名單,息屏後五分鐘之內應用都殺了,簡單開啟後臺任務白名單,息屏不會被殺,但是藍芽連線經常被斷開,後臺無法開啟掃描,點亮螢幕才會正常工作,解決辦法,開啟所有的白名單吧。
小米: 開啟白名單之後就可以正常使用了,但是如果一開始在未開啟白名單的狀態下使用藍芽,多次掃描後,會報告藍芽掃描錯誤,只有開啟白名單,重啟藍芽才可以。
OV: 這倆手機開啟基本的白名單之後還需要額外確認是否開啟的定位許可權,閉著用來測試的OV系統版本中定位許可權開關很深,所以特別提一下。
魅族:基本的白名單即可;
三星:開啟只能管理器中白名單之後就可以隨意折騰了。
Nexus/Piexl:低版本隨意折騰,7.0以後有一些簡單的電量管理白名單可以開啟。
請善待那些信任你放開手讓你折騰的ROM! Orz.
5.關於與硬體裝置之間的連線引數設定
在與硬體進行除錯的過程中發現,Android相比於iOS的BLE連線在每次連線後都會預設去更新連線引數,不知道是否與各家定製的ROM有關。
6.掃描模式引數與連線模式引數設定
在藍芽掃描方法中提供了一個掃描模式引數:
final ScanSettings scanSettings = new ScanSettings.Builder() .setScanMode(mScanMode) .build();
這裡的掃描模式有三種:
ScanSettings.SCAN_MODE_LOW_POWER
:節省功耗優先。
ScanSettings.SCAN_MODE_BALANCED
:功耗與效率平衡。
ScanSettings.SCAN_MODE_LOW_LATENCY
:效率優先優先。
可根據需求進行選擇
在BLE連線的方法中,提供了一個連線模式引數:
mBluetoothGatt = device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
這裡的模式選擇有三種:
BluetoothDevice.TRANSPORT_AUTO
:對於GATT連線到遠端雙模裝置無物理傳輸優先。
BluetoothDevice.TRANSPORT_BREDR
:GATT連線到遠端雙模裝置優先BR/EDR。
BluetoothDevice.TRANSPORT_LE
:GATT連線到遠端雙模裝置優先BLE。
這裡選擇優先BLE。