Android BLE 读写

Creative Commons
本作品采用知识共享署名

本文简要介绍如何在Android中进行BLE device的读写,实验平台Android 7, 编译SDK 28(android 9).

本文说明在Android BLE Connect connect到device后继续进行数据读写.

获取读写对象

Characteristic

通过UUID从service中找到要读写的Characteristic,例如我这里打算读温度

1
2
3
4
5
private static final UUID TEMPE_CHARACTERISTIC_UUID = UUID.fromString("00002A6E-0000-1000-8000-00805f9b34fb");
BluetoothGattCharacteristic mSchr;
for(BluetoothGattService ser: mServiceList){
mSchr = ser.getCharacteristic(TEMPE_CHARACTERISTIC_UUID);
}

Descriptor

通过UUID从Characteristic中找到要读写的Descriptor,例如我这里打算读温度传感器测量的Trigger方式

1
2
3
4
5
6
7
8
9
10
11
private static final UUID EST_DESCRIPTOR_UUID = UUID.fromString("0000290d-0000-1000-8000-00805f9b34fb");
BluetoothGattDescriptor mSdes;
for(BluetoothGattService ser: mServiceList){

List<BluetoothGattCharacteristic> chrs = ser.getCharacteristics();

for(BluetoothGattCharacteristic chr:chrs){
mSdes = chr.getDescriptor(EST_DESCRIPTOR_UUID);
break;
}
}

读&写

值得注意的是无论读写都是异步的,在调用读/写API后需要等到回调执行后才能再调用读/写API,如果回调发生之前调用读/写API无效

Characteristic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//发起读
mGatt.readCharacteristic(mSchr);

//mGattCallback(BluetoothGattCallback) 中重写onCharacteristicRead
//当读完成后,会回调中重写onCharacteristicRead,使用getXXXValue取回数据
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
mStr = " ";
if (characteristic.getUuid().equals(TEMPE_CHARACTERISTIC_UUID)) {
//温度是以u16_t传输,因此按照FORMAT_UINT16读
mStr = "Temp: " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0);
}

mShowString.add(mStr);
}

}

回调中通过getValue有下面几种方式,这个需要根据使用的GATT profiles定义或自定义的Characteristic 的Value格式来决定给用那种

  • byte[] getValue()
  • Integer getIntValue(int formatType, int offset)
  • Float getFloatValue(int formatType, int offset)
  • String getStringValue(int offset)

Characteristic的写和Descriptor类似,见后面Descriptor的说明,步骤大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
//写入
mStr.setValue(xxx);
mGatt.writeCharacteristic(mStr);

//等待回调通知完成写入
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
//写入完成
}
}

和getXXXValue,写入也有对应的一组

  • boolean setValue(byte[] value)
  • boolean setValue(int value, int formatType, int offset)
  • boolean setValue(int mantissa, int exponent, int formatType, int offset)
  • boolean setValue(String value)

Descriptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//发起读
mGatt.readDescriptor(mSdes);

//mGattCallback(BluetoothGattCallback) onDescriptorRead
//当读完成后,会回调中重写onDescriptorRead,使用getValue取回数据
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
mStr = " ";

if(descriptor.getUuid().equals(EST_DESCRIPTOR_UUID)){
byte[] x = descriptor.getValue();
mStr = "Name: " + x[0];
}

mShowString.add(mStr);
}
}

与Characteristic不一样Descriptor的读取数据只有byte[] getValue() ,那回的是ram数据完全靠自己解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//写入
byte[] x = new byte[]{2};
mSdes.setValue(x);
mGatt.writeDescriptor(mSdes);

//mGattCallback(BluetoothGattCallback) onDescriptorWrite
//当写完成后,会回调中重写onDescriptorWrite,之后方可进行下一次读写
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
if(descriptor.getUuid().equals(EST_DESCRIPTOR_UUID)){
mHandler.post(new Runnable() {

@Override
public void run() {
Toast.makeText(MainActivity.this, "Write Des done", Toast.LENGTH_SHORT).show();
}
});
}
}
}

和Descriptor读一样,写入也只有boolean setValue(byte[] value),需要又使用者自己控制raw数据

参考

https://developer.android.com/guide/topics/connectivity/bluetooth-le#read