【笔记】一个实现多连接的蓝牙BLE的简单封装

自己简单封装了一个可以实现多连接的蓝牙BLE的库,主要对蓝牙扫描、连接、接受广播通知、写数据进行了封装,一个功能不是很复杂的BLEManager实现蓝牙BLE的多连接。

完整项目放在github


扫描

提供了一个可以设置超时的扫描方法,主要是考虑到蓝牙扫描比较耗电,扫描使用了职责更为清晰的BluetoothLeScanner。
    /**
     * 扫描
     * @param view
     */
    public void scan(View view) {
        bleManager.startScan(10000, new BLEScanner.OnBLEScanListener() {

            @Override
            public void onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
                synchronized (MainActivity.this){
                    if(!macList.contains(device.getAddress())){
                        macList.add(device.getAddress());
                        adapter.notifyDataSetChanged();
                    }
                }
            }

            @Override
            public void onScanFailed(BLEException bleException) {
                toast(bleException.getMessage());
            }
        });
    }

连接

连接其实可以分为两步,首先是与指定的设备进行连接,然后是找服务。
为了实现多连接创建了一个BluetoothGatt的缓存池,缓存池里主要存放每个mac地址对应的设备的BluetoothGatt和BluetoothGattCallback回调方法,设备连接成功或断开连接、找到服务、接受广播通知、写数据成功、获取到设备返回数据等后面要用到的几个事件都是在BluetoothGattCallback中获取到事件的回调的。
    /**
     * 连接设备
     *
     * @param mac
     * @param onBLEConnectListener
     */
    public void connect(final String mac, final OnBLEConnectListener onBLEConnectListener) {
        BLEGattCallback bleGattCallback = bleBluetoothGattPool.getBluetoothGattCallback(mac);
        if (bleGattCallback == null) {
            bleGattCallback = new BLEGattCallback();
        }
        bleGattCallback.setOnBLEConnectListener(new OnBLEConnectListener() {
            @Override
            public void onConnectSuccess(BluetoothGatt gatt, int status, int newState) {
                onBLEConnectListener.onConnectSuccess(gatt, status, newState);
            }

            @Override
            public void onConnectFailure(BluetoothGatt gatt, BLEException bleException) {
                if (gatt != null) {
                    disconnectGatt(mac);
                }
                if (gatt != null && gatt.getDevice().getAddress().toUpperCase().equals(mac.toUpperCase())) {
                    BLELogUtil.e(TAG, "onConnectFailure");
                    onBLEConnectListener.onConnectFailure(gatt, bleException);
                }
            }

            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                onBLEConnectListener.onServicesDiscovered(gatt, status);
            }
        });
        BluetoothGatt bluetoothGatt = bleBluetoothGattPool.getBluetoothGatt(mac);
        if (bluetoothGatt == null) {
            //缓存池中不存在改gatt
            bluetoothGatt = new BLEConnect().connect(application, mac, bleGattCallback);
        }
        if (bluetoothGatt == null) {
            onBLEConnectListener.onConnectFailure(null, new BLEException(BLEException.CONNECT_FAILURE));
        }
        //添加到缓存池中
        bleBluetoothGattPool.setBluetoothGatt(mac, bluetoothGatt, bleGattCallback);
    }

写特征值

有时可能需要接受广播通知,需要写入特定特征值,写入成功有回调。
使用时传入服务的uuid,特征值的uuid和要数据返回的特征值的uuid。
        bleManager.writeDescriptor(currentMac, uuidDescriptorService, uuidDescriptorCharacteristic, uuidDescriptor, new OnBLEWriteDescriptorListener() {
            @Override
            public void onWriteDescriptorSuccess(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                toast("接受通知成功");
            }

            @Override
            public void onWriteDescriptorFailure(BLEException bleException) {
                toast(bleException.getMessage());
            }
        });

写数据

写数据主要是封装了一个分包写数据,之前说过蓝牙BLE发数据每包是有限制的MTU是23,进行分包每次写入20个数据,同时两包数据之间进行一定的时间间隔,虽然蓝牙传输是可靠的数据传输方式,理论上是不会出现丢包的现象的,但是太过频繁的发送数据还是出现了丢包现象。
    /**
     * 写一组数据
     *
     * @param gatt
     * @param gattCallback
     * @param bluetoothGattCharacteristic
     * @param data
     * @param position
     */
    private void writeOneSet(final BluetoothGatt gatt, final BLEGattCallback gattCallback, final BluetoothGattCharacteristic bluetoothGattCharacteristic, final byte[] data, int position) {
        currentPosition = position;
        if (position == 0) {
            //第一组数据
            gattCallback.setOnBLEWriteDataListener(new OnBLEWriteDataListener() {
                @Override
                public void onWriteDataSuccess(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                    if ((currentPosition + 1) * MAX_BYTES >= data.length) {
                        //数据完全写完
                        onBLEWriteDataListener.onWriteDataSuccess(gatt, characteristic, status);
                        return;
                    }
                    writeOneSet(gatt, gattCallback, bluetoothGattCharacteristic, data, currentPosition + 1);
                }

                @Override
                public void onWriteDataFailure(BLEException exception) {
                    onBLEWriteDataListener.onWriteDataFailure(exception);
                }
            });
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //两包数据间间隔一定时间
                    Thread.sleep(WAIT_TIME);
                    int sendLength = data.length - currentPosition * MAX_BYTES;
                    sendLength = sendLength > MAX_BYTES ? MAX_BYTES : sendLength;
                    byte[] sendValue = BLEByteUtil.getSubbytes(data, currentPosition * MAX_BYTES, sendLength);
                    BLELogUtil.i(TAG, String.format("position=%d,%s", currentPosition, BLEByteUtil.bytesToHexString(sendValue)));
                    if (!bluetoothGattCharacteristic.setValue(sendValue)) {
                        BLELogUtil.e(TAG, "writeOneSet setValue failure");
                        onBLEWriteDataListener.onWriteDataFailure(new BLEException(BLEException.WRITE_DATA_FAILURE));
                        return;
                    }
                    if (!gatt.writeCharacteristic(bluetoothGattCharacteristic)) {
                        BLELogUtil.e(TAG, "writeOneSet writeCharacteristic failure");
                        onBLEWriteDataListener.onWriteDataFailure(new BLEException(BLEException.WRITE_DATA_FAILURE));
                        return;
                    }
                } catch (Exception e) {
                    BLELogUtil.e(TAG, "writeOneSet e:" + e.getMessage());
                }
            }
        }).start();
    }

源码







猜你喜欢

转载自blog.csdn.net/q1113225201/article/details/72228854