AndroidBLE開發(fā)過(guò)程中遇到的問(wèn)題記錄

Android BLE 開發(fā)過(guò)程中遇到的問(wèn)題記錄

1.斷開連接后出現(xiàn)133錯(cuò)誤

在斷開連接之后再次連接經(jīng)常會(huì)出現(xiàn)133錯(cuò)誤,并且難以連接成功,處理方式如下:

首先在重連的時(shí)候先將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;

再次連接時(shí),使用一個(gè)全新的Gatt對(duì)象進(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錯(cuò)誤, 不能發(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);
           }
       }
    }

這種操作下來(lái)即使出現(xiàn)133,也能在多次嘗試重連之后連接成功。

其次,出現(xiàn)133也很有可能與硬件有關(guān),筆者使用的硬件硬件在初期經(jīng)常出現(xiàn)133錯(cuò)誤,但硬件進(jìn)行了調(diào)優(yōu)之后出現(xiàn)的頻率大大降低了,所以并不是所有的問(wèn)題都是Android設(shè)備的錯(cuò)。

2.交互時(shí)出現(xiàn)128錯(cuò)誤

開發(fā)過(guò)程中命令交互的時(shí)候出現(xiàn)128錯(cuò)誤,連接中止:

這個(gè)錯(cuò)誤出現(xiàn)的原因是因?yàn)間att命令交互并不能并行操作,一旦上一個(gè)命令還未反饋結(jié)束就再次發(fā)送下一個(gè)命令就會(huì)出現(xiàn)128錯(cuò)誤。

3.發(fā)現(xiàn)服務(wù)之后立即進(jìn)行連接,部分機(jī)型無(wú)法成功

在開發(fā)過(guò)程中發(fā)現(xiàn),建立連接過(guò)程中,發(fā)現(xiàn)服務(wù)之后如果立即書寫特征值,可能出現(xiàn)部分機(jī)型無(wú)法成功連接的情況:

通過(guò)長(zhǎng)期測(cè)試,目前將每一條特征值的書寫進(jìn)行了700ms的延遲,暫時(shí)可以支持絕大部分機(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)牙命令交互時(shí)串行的所以在開發(fā)過(guò)程中對(duì)此必須嚴(yán)格遵守,異常出現(xiàn)的并行命令極有可能造成各種問(wèn)題,而且不容易定位bug,當(dāng)然這部分可以使用第三方封裝好的庫(kù)來(lái)做。

5.各品牌手機(jī)省電策略引起的問(wèn)題

華為: 非常嚴(yán)格,如果不開啟任何白名單,息屏后五分鐘之內(nèi)應(yīng)用都?xì)⒘?,?jiǎn)單開啟后臺(tái)任務(wù)白名單,息屏不會(huì)被殺,但是藍(lán)牙連接經(jīng)常被斷開,后臺(tái)無(wú)法開啟掃描,點(diǎn)亮屏幕才會(huì)正常工作,解決辦法,開啟所有的白名單吧。

小米: 開啟白名單之后就可以正常使用了,但是如果一開始在未開啟白名單的狀態(tài)下使用藍(lán)牙,多次掃描后,會(huì)報(bào)告藍(lán)牙掃描錯(cuò)誤,只有開啟白名單,重啟藍(lán)牙才可以。

OV: 這倆手機(jī)打開基本的白名單之后還需要額外確認(rèn)是否開啟的定位權(quán)限,閉著用來(lái)測(cè)試的OV系統(tǒng)版本中定位權(quán)限開關(guān)很深,所以特別提一下。

魅族:基本的白名單即可;

三星:開啟只能管理器中白名單之后就可以隨意折騰了。

Nexus/Piexl:低版本隨意折騰,7.0以后有一些簡(jiǎn)單的電量管理白名單可以開啟。

請(qǐng)善待那些信任你放開手讓你折騰的ROM! Orz.

5.關(guān)于與硬件設(shè)備之間的連接參數(shù)設(shè)置

在與硬件進(jìn)行調(diào)試的過(guò)程中發(fā)現(xiàn),Android相比于iOS的BLE連接在每次連接后都會(huì)默認(rèn)去更新連接參數(shù),不知道是否與各家定制的ROM有關(guān)。

6.掃描模式參數(shù)與連接模式參數(shù)設(shè)置

在藍(lán)牙掃描方法中提供了一個(gè)掃描模式參數(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連接的方法中,提供了一個(gè)連接模式參數(shù):

    mBluetoothGatt = device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);

這里的模式選擇有三種:

BluetoothDevice.TRANSPORT_AUTO:對(duì)于GATT連接到遠(yuǎn)程雙模設(shè)備無(wú)物理傳輸優(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。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容