Context

最近做了三个涉及蓝牙的小应用,都有Android版本。说实话,写了一年多Android(完完整整的写)。我对Android的蓝牙链接状态还是存在一些不明确的地方。

毕竟最早接触的是iOS的蓝牙开发,接触新领域的时候总是会根据以前的认知来加以理解。

iOS

iOS上面对蓝牙外设的连接状态是通过BluetoothCentralManager来告知的。

@protocol CBCentralManagerDelegate <NSObject>

//外设链接成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
//外设连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
//外设已断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;

所以蓝牙是否连接成功是通过中心来通知的,但是在Android上,连接状态是由外设来通知的

Android

public final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
    }
}

其中status代表了GATT操作的成功与失败,newState代表了GATT的新状态

status有GATT_SUCCESS,GATT_FAIL

newState有STATE_CONNECTED,STATE_CONNECTING,STATE_DISCONNECTED,STATE_DISCONNECTING

所以这个回调函数可以出现8种状态。

State

那么,对比上面iOS的三个协议,列一张对比表

状态 iOS Android
已连接 didConnectPeripheral GATT_SUCCESS+STATE_CONNECTED
已断开 didDisconnectPeripheral GATT_SUCCESS+STATE_DISCONNECTED,GATT_FAIL+STATE_DISCONNECTED
连接失败 didFailToConnectPeripheral GATT_FAIL+STATE_CONNECTED

可以看到已断开这里,android有两种可能性,第一种是系统底层发现连接断开了GATT_FAIL+STATE_DISCONNECTED,另外一种是用户控制断开GATT_SUCCESS+STATE_DISCONNECTED。
这并不是说明iOS的接口设计的不够周到,而只是iOS把断开的原因放在了error里面而已。

Disconnect

在iOS里断开外设的连接实在是简单。只要让centralManager cancel Connection就可以了。但是在android中,会发现有两个方法~disconnect(),close()

感觉好像两个方法都是对的样子,但实际上他们是有区别的。

BLE通信从底层来说,是在每个connection中传递数据的。所以disconnect是指停止connection通信,但是并没有断开连接。当gatt disconnect了之后,再使用close()便可以真正的断开连接。

假设直接使用close()会怎样呢?

其实不会怎样,蓝牙照样断开了,只不过不会在BluetoothGattCallback中通知。这或许对于开发者来说,会比较麻烦。因为像我就是在BluetoothGattCallback中来定义外设的连接状态,并使用event来通知相关的组件和界面做操作的。
直接close()对于蓝牙来说就会出现一个延迟,因为没有disconnect的蓝牙外设完全断开需要花点时间。

End

这一篇blog是写了一年多Android蓝牙后,从一次次的项目中慢慢总结的。现在回过去看最早最早做的蓝牙类,那是真的漏洞百出啊。

现在感觉自己封装的蓝牙库,和iOS越来越接近了。这样以后写完iOS,再写android会更方便~有点儿爽。