Android BLE连接 status =133优化

6,219 阅读2分钟

这里声明一下,这篇文章仅仅针对有一定蓝牙开发基础的同学。

Android BLE开发是个大坑, 连接很不稳定。 多次连接外围设备时, 就会出现连接失败的情况。 观察日志发现 onClientConnectionState() 方法经常出现133 的错误码。

1、 为什么会出现 133的错误码

  • gatt.close()没有调用,资源没有释放导致连接失败
  • 频繁尝试建立连接
  • 系统对Ble最大的连接数量是有限制的,一般最大的连接数量为6, 超过这个限制就会出现133错误码
  • BLE硬件模块问题

企业微信截图_7764908e-2405-4daa-b5f9-6ff6069c9010.png

如何解决?

2、 GATT每次连接前, close之前的资源

    // 全局gatt
    private BluetoothGatt mGatt;

    private void connect(BluetoothDevice device, BluetoothGattCallback callback) {
        // 释放上次gatt连接资源
        close();
        if (SdkUtil.isAtLeastM_23()) {
            mGatt = device.connectGatt(ViotSDK.getInstance().getBaseContext(), false, callback, BluetoothDevice.TRANSPORT_LE);
        } else {
            mGatt = device.connectGatt(ViotSDK.getInstance().getBaseContext(), false, callback);
        }
    }

    // 释放上次gatt连接资源
    public void close() {
        if (mGatt != null) {
            mGatt.disconnect();
            mGatt.close();
            mGatt = null;
        }
    }

3、清理Gatt缓存

在重连的时候先将Gatt缓存进行清理:

    public boolean refreshDeviceCache() {
        try {
            VLog.d(TAG, "clear gatt cache");
            BluetoothGatt localBlueToothGatt = mBluetoothGatt;
            Method localMethod = localBlueToothGatt.getClass().getMethod("refresh", new Class[0]);
            if (localMethod != null) {
                localMethod.setAccessible(true);
                Boolean bool = ((Boolean) localMethod.invoke(localBlueToothGatt, new Object[0])).booleanValue();
                localMethod.setAccessible(false);
                return bool;
            }
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }

        return false;
    }

然后进行close操作:

    mBluetoothGatt.close();
    mBluetoothGatt = null;

4、 出现133错误码时, 进行重试策略

在Gatt连接的回调中,如果连接失败,并且错误码是133时,进行重试连接

    // 重试连接三次
    private static int GATT_CONNECT_RETRY_MAX_COUNT = 3;
    private int retryCount = 0;
    
    private class BleCallback extends BluetoothGattCallback {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (BluetoothGatt.GATT_SUCCESS == status) { // gatt连接成功

            } else { // gatt连接失败
                // 连接失败需要释放资源
                close();
                if (status == 133 && retryCount < GATT_CONNECT_RETRY_MAX_COUNT) { // 133错误码重试
                    connect(deviice, callback);
                }
            }
        }
    }

由于设备 Rom是公司系统组自己定制的, 所以开关蓝牙的操作是有权限的。 我们可以在重试的过程中, 对设备蓝牙进行重启,更彻底的释放蓝牙连接。

    // 重试连接三次
    private static int GATT_CONNECT_RETRY_MAX_COUNT = 3;
    prvate int retryCount = 0;

    private Handler handler = new Handler(Looper.myLooper());

    private class BleCallback extends BluetoothGattCallback {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (BluetoothGatt.GATT_SUCCESS == status) { // gatt连接成功

            } else { // gatt连接失败
                // 释放资源
                close();
                if (status == 133 && retryCount < GATT_CONNECT_RETRY_MAX_COUNT) {
                    if (BluetoothUtil.switchBlueState(false)) { // 关闭蓝牙
                        handler.postDelayed(() -> {
                            if (BluetoothUtil.switchBlueState(true)) { // 5s后,开启蓝牙
                                handler.postDelayed(new Runnable() { // 5s后重试连接设备
                                    @Override
                                    public void run() {
                                        connect(deviice, callback);
                                    }
                                }, 5000);
                            } else {
                                // 重新打开蓝牙失败
                                connectDeviceError();
                            }
                        }, 5000);
                    } else {
                        // 关闭蓝牙失败
                        connectDeviceError();
                    }
                }
            }
        }

        private void connectDeviceError() {
        }
    }

蓝牙操作类BluetoothUtil

public class BluetoothUtil {

    private static final String TAG = BluetoothUtil.class.getSimpleName();

    /**
     * 切换蓝牙开关状态
     */
    public static boolean switchBlueState(boolean isOpen) {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

        boolean suc;
        if (isOpen) {
            suc = adapter.enable();
            Log.d(TAG, "open blue suc :" + suc);
        } else {
            suc = adapter.disable();
            Log.d(TAG, "close blue suc :" + suc);
        }

        return suc;
    }
}

5、 FastBLe

地址:github.com/Jasonchenli…

FastBLe 是一个优秀的BLE开源库,在GitHub有4.4K Star, 支持重连机制,连接设备较稳定。

WeChat6963fbd2868b8c93d53165b185204114.png

6、 总结

经过多次优化, 发现并不能完全杜绝133的错误码的出现,只能减少133的出现。
这个问题也和机型有关, 我尝试的小米连接较稳定, oppo经常出现。在Ble开发中,容易遇到。还是需要谷歌在协议层, 设备厂商在硬件层进行优化。 开发能做的是尽可能的提高Ble连接的稳定性。
大家如果有更好的办法, 欢迎在评论区讨论

参考:

stackoverflow.com/questions/2…

medium.com/@martijn.va…

www.zhihu.com/question/24…

github.com/Jasonchenli…