1

写入特定特征会使应用程序崩溃并引发以下异常:

Caused by: BleGattException{status=8, bleGattOperation=BleGattOperation{description='CHARACTERISTIC_WRITE'}}
      at com.polidea.rxandroidble.internal.connection.RxBleGattCallback.propagateStatusErrorIfGattErrorOccurred(RxBleGattCallback.java:245)
      at com.polidea.rxandroidble.internal.connection.RxBleGattCallback.access$100(RxBleGattCallback.java:26)
      at com.polidea.rxandroidble.internal.connection.RxBleGattCallback$1.onCharacteristicWrite(RxBleGattCallback.java:110)
      at android.bluetooth.BluetoothGatt$1.onCharacteristicWrite(BluetoothGatt.java:407)
      at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:279)

与设备建立了连接,其他读写方法似乎都可以正常工作。

正在使用的代码:

mConnectoin.writeCharacteristic(UUID, bytes)
    .observeOn(AndroidSchedulers.mainThread());

我的第一个想法是,也许该特征没有启用写权限,但以下日志语句characteristic.getProperties()返回 8,表明它确实具有写权限:

.getCharacteristic(CharacteristicUUID)
                    .subscribe(new Action1<BluetoothGattCharacteristic>() {
                        @Override
                        public void call(BluetoothGattCharacteristic characteristic) {
                            Log.d(TAG, "characteristic permissions: " + characteristic.getPermissions());
                            Log.d(TAG, "characteristic properties: " + characteristic.getProperties());
                        }
                    });

那么问题可能是什么?

4

2 回答 2

2
于 2016-10-14T14:03:19.477 回答
1

正如@s_noopy 所指出的,在库中配对设备没有具体的支持,但是有一些选项可以创建你的小助手,可以在连接之前为你提供帮助。

RxBluetooth 库支持以反应方式进行绑定。

我提取了特定的代码片段,并创建了一个小要点来分享(仅用于绑定过程)。随意分叉或改进它(代码基于 RxBluetooth)。另外,如果有人找到更好的方法或有问题,请指出!

原始要点

更新

我修改了RxBluetooth(以前称为RxBluetoothHelper)的源代码,因为在进行解绑定时存在错误。在Android中,当您绑定时,您必须在意图中监听绑定过程(但是当您取消绑定时,系统只是删除存储的密钥)。这个更新的版本解决了以前没有的问题。此外,如果由于某种原因,当您调用bond 时,该方法返回false,则observable 将发出onError。要点也更新了!


public class BluetoothCompat {

    public static boolean createBondCompat(final BluetoothDevice device)
    throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            return device.createBond();
            } else {
            Method method = device.getClass().getMethod("createBond", (Class[]) null);
            final Object invoke = method.invoke(device, (Object[]) null);
            return (Boolean) invoke;
        }
    }

    public static boolean removeBondCompat(final BluetoothDevice device) throws NoSuchMethodException, InvocationTargetException,
    IllegalAccessException {
        Method method = device.getClass().getMethod("removeBond", (Class[]) null);
        final Object invoke = method.invoke(device, (Object[]) null);
        return (Boolean) invoke;
    }

    private BluetoothCompat() {
        throw new AssertionError("No instances!");
    }

}

public class RxBluetooth {

    private final Context context;
    private final BluetoothAdapter adapter;

    private static final Observable.Transformer BOND_STATUS_TRANSFORMER = statusObservable -> statusObservable.map(status -> {
        switch (status) {
            case BluetoothDevice.BOND_NONE:
            default:
            return BondStatus.NONE;
            case BluetoothDevice.BOND_BONDING:
            return BondStatus.BONDING;
            case BluetoothDevice.BOND_BONDED:
            return BondStatus.BONDED;
        }
    });

    public enum BondStatus {
        NONE,
        BONDING,
        BONDED
    }

    public RxBluetooth(Context context, BluetoothAdapter bluetoothAdapter) {
        this.context = context.getApplicationContext();
        this.adapter = bluetoothAdapter;
    }

    public Observable bondStatus(@NonNull final BluetoothDevice device) {
        return Observable.defer(() -> Observable.just(device.getBondState()).compose(BOND_STATUS_TRANSFORMER));
    }

    public Observable bond(@NonNull final BluetoothDevice device) {
        return Observable.create(subscriber -> {
            bondStatus(device).subscribe(bondStatus -> {
                switch (bondStatus) {
                    case NONE:
                    observeDeviceBonding(context, device).compose(BOND_STATUS_TRANSFORMER).subscribe(subscriber);
                    try {
                        final boolean bonding = BluetoothCompat.createBondCompat(device);
                        if (!bonding) {
                            subscriber.onError(new BluetoothBondingException("Can't initiate a bonding operation!"));
                        }
                        } catch (Exception e) {
                        subscriber.onError(new BluetoothIncompatibleBondingException(e));
                    }
                    break;
                    case BONDING:
                    subscriber.onError(new BluetoothBondingException("device is already in the process of bonding"));
                    break;
                    case BONDED:
                    subscriber.onNext(BondStatus.BONDED);
                    subscriber.onCompleted();
                    break;
                }
            });
        });
    }

    public Observable removeBond(@NonNull final BluetoothDevice device) {
        return Observable.defer(() -> {

            for (BluetoothDevice bondedDevice : adapter.getBondedDevices()) {
                if (bondedDevice.getAddress().equals(device.getAddress())) {
                    try {
                        final boolean removeBond = BluetoothCompat.removeBondCompat(device);
                        if (!removeBond) {
                            return Observable.error(new BluetoothBondingException("Can't delete the bonding for this device!"));
                        }
                        } catch (Exception e) {
                        return Observable.error(new BluetoothIncompatibleBondingException(e));
                    }
                }
            }

            return Observable.just(BondStatus.NONE);
        });
    }

    private static Observable observeDeviceBonding(@NonNull final Context context, @NonNull final BluetoothDevice device) {
        return observeBroadcast(context, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)).filter(pair -> {
            BluetoothDevice bondingDevice = pair.getValue1().getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            return bondingDevice.equals(device);
        })
        .map(pair1 -> pair1.getValue1().getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1))
        .skipWhile(state -> state != BluetoothDevice.BOND_BONDING)
        .takeUntil(state -> state == BluetoothDevice.BOND_BONDED || state == BluetoothDevice.BOND_NONE);
    }

    private static Observable> observeBroadcast(final Context context, final IntentFilter filter) {
        return Observable.create(new Observable.OnSubscribe>() {

            @Override public void call(Subscriber> subscriber) {
                Enforcer.onMainThread();

                final BroadcastReceiver receiver = new BroadcastReceiver() {
                    @Override public void onReceive(Context context, Intent intent) {
                        subscriber.onNext(Pair.with(context, intent));
                    }
                };

                context.registerReceiver(receiver, filter);

                subscriber.add(Subscriptions.create(() -> context.unregisterReceiver(receiver)));
            }
        });
    }

}
于 2016-10-14T15:01:45.723 回答