Android BLE 開發(fā)過程中遇到的問題記錄
1.斷開連接后出現(xiàn)133錯誤
在斷開連接之后再次連接經(jīng)常會出現(xiàn)133錯誤景东,并且難以連接成功,處理方式如下:
首先在重連的時候先將Gatt緩存進(jìn)行清理:
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連接進(jìn)行close操作:
mBluetoothGatt.close();
mBluetoothGatt = null;
再次連接時拱礁,使用一個全新的Gatt對象進(jìn)行連接操作,而且在連接之前再次確認(rèn)Gatt連接是否已經(jīng)釋放:
/**
* 連接設(shè)備Gatt
*
* @param device 設(shè)備
*/
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;
}
//防止連接出現(xiàn)133錯誤, 不能發(fā)現(xiàn)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);
}
}
}
這種操作下來即使出現(xiàn)133,也能在多次嘗試重連之后連接成功辕漂。
其次呢灶,出現(xiàn)133也很有可能與硬件有關(guān),筆者使用的硬件硬件在初期經(jīng)常出現(xiàn)133錯誤钮热,但硬件進(jìn)行了調(diào)優(yōu)之后出現(xiàn)的頻率大大降低了填抬,所以并不是所有的問題都是Android設(shè)備的錯。
2.交互時出現(xiàn)128錯誤
開發(fā)過程中命令交互的時候出現(xiàn)128錯誤隧期,連接中止:
這個錯誤出現(xiàn)的原因是因?yàn)間att命令交互并不能并行操作飒责,一旦上一個命令還未反饋結(jié)束就再次發(fā)送下一個命令就會出現(xiàn)128錯誤。
3.發(fā)現(xiàn)服務(wù)之后立即進(jìn)行連接仆潮,部分機(jī)型無法成功
在開發(fā)過程中發(fā)現(xiàn)宏蛉,建立連接過程中,發(fā)現(xiàn)服務(wù)之后如果立即書寫特征值性置,可能出現(xiàn)部分機(jī)型無法成功連接的情況:
通過長期測試拾并,目前將每一條特征值的書寫進(jìn)行了700ms的延遲,暫時可以支持絕大部分機(jī)型鹏浅。
@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藍(lán)牙命令交互確保是有序串行的
由于BLE藍(lán)牙命令交互時串行的所以在開發(fā)過程中對此必須嚴(yán)格遵守嗅义,異常出現(xiàn)的并行命令極有可能造成各種問題,而且不容易定位bug隐砸,當(dāng)然這部分可以使用第三方封裝好的庫來做之碗。
5.各品牌手機(jī)省電策略引起的問題
華為: 非常嚴(yán)格,如果不開啟任何白名單季希,息屏后五分鐘之內(nèi)應(yīng)用都?xì)⒘送誓牵唵伍_啟后臺任務(wù)白名單幽纷,息屏不會被殺,但是藍(lán)牙連接經(jīng)常被斷開博敬,后臺無法開啟掃描友浸,點(diǎn)亮屏幕才會正常工作,解決辦法偏窝,開啟所有的白名單吧收恢。
小米: 開啟白名單之后就可以正常使用了,但是如果一開始在未開啟白名單的狀態(tài)下使用藍(lán)牙囚枪,多次掃描后派诬,會報(bào)告藍(lán)牙掃描錯誤劳淆,只有開啟白名單链沼,重啟藍(lán)牙才可以。
OV: 這倆手機(jī)打開基本的白名單之后還需要額外確認(rèn)是否開啟的定位權(quán)限沛鸵,閉著用來測試的OV系統(tǒng)版本中定位權(quán)限開關(guān)很深括勺,所以特別提一下。
魅族:基本的白名單即可曲掰;
三星:開啟只能管理器中白名單之后就可以隨意折騰了疾捍。
Nexus/Piexl:低版本隨意折騰,7.0以后有一些簡單的電量管理白名單可以開啟栏妖。
請善待那些信任你放開手讓你折騰的ROM乱豆! Orz.
5.關(guān)于與硬件設(shè)備之間的連接參數(shù)設(shè)置
在與硬件進(jìn)行調(diào)試的過程中發(fā)現(xiàn),Android相比于iOS的BLE連接在每次連接后都會默認(rèn)去更新連接參數(shù)吊趾,不知道是否與各家定制的ROM有關(guān)宛裕。
6.掃描模式參數(shù)與連接模式參數(shù)設(shè)置
在藍(lán)牙掃描方法中提供了一個掃描模式參數(shù):
final ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(mScanMode)
.build();
這里的掃描模式有三種:
ScanSettings.SCAN_MODE_LOW_POWER
:節(jié)省功耗優(yōu)先。
ScanSettings.SCAN_MODE_BALANCED
:功耗與效率平衡论泛。
ScanSettings.SCAN_MODE_LOW_LATENCY
:效率優(yōu)先優(yōu)先揩尸。
可根據(jù)需求進(jìn)行選擇
在BLE連接的方法中,提供了一個連接模式參數(shù):
mBluetoothGatt = device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
這里的模式選擇有三種:
BluetoothDevice.TRANSPORT_AUTO
:對于GATT連接到遠(yuǎn)程雙模設(shè)備無物理傳輸優(yōu)先屁奏。
BluetoothDevice.TRANSPORT_BREDR
:GATT連接到遠(yuǎn)程雙模設(shè)備優(yōu)先BR/EDR岩榆。
BluetoothDevice.TRANSPORT_LE
:GATT連接到遠(yuǎn)程雙模設(shè)備優(yōu)先BLE。
這里選擇優(yōu)先BLE坟瓢。