写入特定特征会使应用程序崩溃并引发以下异常:
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());
}
});
那么问题可能是什么?
答案 0 :(得分:2)
BluetoothGattCallback
在onCharacteristicWrite()
类RxBleGattCallback
回调方法中发出。 (它在status
类内)。
status=8
来自Android OS BLE堆栈。例如,这些描述如下:https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h
#define GATT_INSUF_AUTHORIZATION 0x08
表示BluetoothCharacteristic
- 因此您似乎正在尝试编写需要加密连接的RxAndroidBle
(配对设备)。
不幸的是,目前 @Override
@TargetApi(15)
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
row = mActivity.getLayoutInflater().inflate(mLayoutId, null, false);
}
Cursor list_cursor = getCursor();
list_cursor.moveToPosition(position);
if(!list_cursor.isLast()){
list_cursor.moveToNext();
TextView txtSecondCell = (TextView) row.findViewById(R.id.recname_row);
String recipename = list_cursor.getString(list_cursor.getColumnIndex(Recipe.NAME_NIC));
txtSecondCell.setText(recipename);
Log.i(TAG, "Showing List");
}
return row;
}
无法帮助配对设备。
答案 1 :(得分:1)
正如@s_noopy指出的那样,对于在库中配对设备没有特别的支持,但是有一些选项可以创建你的小助手,可以在连接之前为你提供帮助。
RxBluetooth library支持以反应方式进行债券。
我提取了特定的代码片段,并创建了一个小小的要点来分享(只有绑定过程)。随意分叉或改进它(代码基于RxBluetooth)。此外,如果有人找到更好的方法或者出现问题,请指出来!
<强>更新强>
我修改了RxBluetooth
(之前命名为RxBluetoothHelper
)的源代码,因为在进行取消绑定时存在错误。在Android中,当你绑定时,你必须在意图中监听绑定过程(但是当你不需要unbond时,因为系统只删除存储的键)。此更新版本解决了以前没有的问题。此外,如果由于某种原因调用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)));
}
});
}
}