我们在《Android蓝牙开发系列文章-策划篇》中计划讲解一下蓝牙BLE,现在开始第一篇:Android蓝牙开发系列文章-玩转BLE开发(一)。计划要写的BLE文章至少分四篇,其他三篇分别讲解:BLE Server端编码(用手机模拟外围设备),BLE Beacon功能,BLE设备通信(利用自有协议实现Client和Server端通信,在Server端信息改变时,自动上报给Client)。
本文主要内容:编码实现BLE Client端,实现手机与蓝牙体重秤之间的通信
所用的设备:华为荣耀7手机,微信小程序,乐心体重秤
目录
1.基本概念
2.先来认识一下我们的设备
3、认识BLE Client编码
3.1 扫描BLE设备
3.2 建立GATT连接
3.3 解析设备支持的characteristic
3.4 读取characteristic值
3.5 写characteristic值
3.6 设置indication
4、总结
在这里先讲解一下BLE(Bluetooth Low Energy)的一些简单概念。
本文会涉及一个概念叫“GATT连接”,那我们先说一下什么是GATT,GATT(GenericAttribute Profile)译为通用属性配置文件。GATT连接利用的是在外设(体重秤)与中心设备(手机)之间建议一种联系,这种联系利用的是双方之间都能够识别(或者说提前约定好)的协议。这种协议的基础就是GATT。
GATT由service、characteristic、descriptor元素组成。service是一个功能单元的集合,这个集合有SIG标准的,也可以自己定义的。一个service可以包含一个或者多个characteristic,每个characteristic包含一个value和一个或者多个descriptor。descriptor是对characteristic的描述,例如是否支持读取等。
我们说的利用GATT通信就是对characteristic的读、写、或者characteristic的值发生改变时的自动上报(方向为:从蓝牙体重秤到手机)。
一个BLE设备往往支持多个service,即多个功能集合。例如,现在智能电视遥控器也许会支持蓝牙电量的service、蜂鸣的service以及一些自定义的service。
按照我个人的理解,画了一个BLE设备的GATT的结构如下,仅供大家参考。
俗话说“知彼知己,百战不殆”,我们在动手码代码前,要先来了解一下我们所用的设备,不然代码写了一半了,才意识到我们这个功能根本完成不了,那不是呵呵了。
我的测试手机是荣耀7,Android版本为Android6,因为BLE是从Android4.3开始支持的,所以我的手机应该可以过关了。
利用微信小程序“BLE蓝牙开发助手”可以搜索到家里的体脂秤,并且可以建立连接。利用该小程序可以看到该款体重秤有4个service,点击中某个service中的characteristic,可以正常读取数据,说明手机与体重秤之间建立通信应该没有问题。
下面我们要做的就是实现微信小程序类似的功能,与体重秤建立通信,并获取数据。
本文以《Android蓝牙开发系列文章-扫不到蓝牙设备,你的姿势对了吗?》中的代码为基础,进行了添加和修改。
利用微信小程序,我们可以知道体重秤支持UUID为“0000FEE7-0000-1000-8000-00805F9B34FB”的service,所以,我在设备过滤条件里指定了UUID,相关代码如下:
private void startBleScan2() {
// mBluetoothLeScanner.startScan(mScanCallback);
//过滤条件
List bleScanFilters = new ArrayList<>();
// ScanFilter filter = new ScanFilter.Builder().setDeviceAddress("08:7C:BE:48:65:AD").setServiceUuid(ParcelUuid.fromString("0000fee7-0000-1000-8000-00805f9b34fb")).build();
ScanFilter filter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("0000FEE7-0000-1000-8000-00805F9B34FB")).build();
bleScanFilters.add(filter);
//扫描设置
ScanSettings scanSetting = new ScanSettings.Builder().setScanMode(SCAN_MODE_LOW_LATENCY).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).setMatchMode(ScanSettings.MATCH_MODE_STICKY).build();
mBluetoothLeScanner.startScan(bleScanFilters, scanSetting, mScanCallback);
}
在扫描到目标设备后,我们将BluetoothDevice对象记录下来。先停掉BLE扫描,然后发起GATT连接。
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.d(TAG, "onScanResult, result = " + result);
Message msg = new Message();
msg.what = MSG_FIND_TARGET;
msg.obj = result.getDevice();
mHandler.sendMessage(msg);
}
};
mHandler = new Handler(){
@NonNull
@Override
public void dispatchMessage(Message msg) {
Log.d(TAG, "dispatchMessage, msg = " + msg.what);
switch (msg.what) {
case MSG_FIND_TARGET:
mTargetDevice = (BluetoothDevice) msg.obj;
stopBleScan2();
mBluetoothGatt = mTargetDevice.connectGatt(getApplicationContext(), false, mBluetoothGattCallback);
break;
}
}
};
GATT连接调用的是BluetoothDevice::connectGatt(Contextcontext,)方法,先说一下参数的含义。
autoConnect表示是否接着发起gatt连接,若值为false,则表示立即发起连接,若值为true,则表示为等到设备变为available时再发起连接。因为我们这里是扫描到设备后发起连接的,所以直接传入false就OK了。
callback是用于获取连接状态改变的回调,该回调是本文的重点,下面详细讲一下。
/**
* Connect to GATT Server hosted by this device. Caller acts as GATT client.
* The callback is used to deliver results to Caller, such as connection status as well
* as any further GATT client operations.
* The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
* GATT client operations.
*
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param autoConnect Whether to directly connect to the remote device (false) or to
* automatically connect as soon as the remote device becomes available (true).
* @throws IllegalArgumentException if callback is null
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
}
我摘取了部分BluetoothGattCallback中的方法,进行简单的解释:
/**
* This abstract class is used to implement {@link BluetoothGatt} callbacks.
*/
public abstract class BluetoothGattCallback {
//连接状态改变的回调,status为BluetoothGatt#GATT_SUCCESS表示连接成功,
//newState表示连接状态改变后的值,可能值为BluetoothProfile#STATE_DISCONNECTED
//或者为BluetoothProfile#STATE_CONNECTED
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
}
//调用了BluetoothGatt:: discoverServices()方法的回调
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
}
//调用了BluetoothGatt::readCharacteristic()方法的回调,在status值为//BluetoothGatt#GATT_SUCCESS时表示我们想要的值读取成功了
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status) {
}
//调用了BluetoothGatt::writeCharacteristic()方法的回调,在status值为
//BluetoothGatt#GATT_SUCCESS时表示我们对characteristic执行写操作成功了
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
}
//在server端的某个characteristic改变时会回调到这里,当然,前提是设置了//notification
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
}
//在执行了读取descriptor的回调,同样,status值表征了操作是否成功
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
}
//在执行了修改descriptor的回调,status值为BluetoothGatt#GATT_SUCCESS表示修改成了
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
}
}
在onConnectionStateChange()回调中,如果status为BluetoothGatt.GATT_SUCCESS且newState为BluetoothProfile.STATE_CONNECTED,则可以发起service扫描,即获取体重秤所支持的service。
如果newState不为BluetoothProfile.STATE_CONNECTED,则释放gatt连接资源,并重新发起连接。
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.d(TAG, "onConnectionStateChange, status = " + status + ", newState = " + newState);
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
} else {
mBluetoothGatt.close();
mBluetoothGatt = mTargetDevice.connectGatt(getApplicationContext(), false, mBluetoothGattCallback);
}
}
}
在搜索完成体重秤的service后,应用层会收到onServiceDiscovered()回调。我们按照service->characteristic->descriptor层次结构,进行解析。
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(TAG, "onServicesDiscovered, status = " + status);
List gattServicesList = mBluetoothGatt.getServices();
parseService(gattServicesList);
}
private void parseService(List gattServiceList) {
Log.d(TAG, "----- start parseServie -----");
for (int i = 0; i < gattServiceList.size(); i++) {
BluetoothGattService gattService = (BluetoothGattService)gattServiceList.get(i);
UUID uuid = gattService.getUuid();
Log.d(TAG, "parseService, service uuid = " + uuid);
List gattCharacteristics = gattService.getCharacteristics();
for (int j = 0; j < gattCharacteristics.size(); j++) {
BluetoothGattCharacteristic gattCharacteristic = gattCharacteristics.get(j);
int properties = gattCharacteristic.getProperties();
int permission = gattCharacteristic.getPermissions();
Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " properties = " + properties);
if (0 != (properties & BluetoothGattCharacteristic.PROPERTY_READ)) {
Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support read");
if (gattCharacteristic.getUuid().toString().equals(LeXinUUID.READ_CHARA)) {
Message msg = new Message();
msg.what = MSG_READ_CHARA;
msg.obj = gattCharacteristic;
mHandler.sendMessageDelayed(msg, DELAY_TIMES);
}
// mBluetoothGatt.readCharacteristic(gattCharacteristic);
}
if ((0 != (properties & BluetoothGattCharacteristic.PROPERTY_INDICATE))) {
Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support indicate");
if (gattCharacteristic.getUuid().toString().equals(LeXinUUID.INDICATE_CHARA)) {
Message msg = new Message();
msg.what = MSG_INDICATE;
msg.obj = gattCharacteristic;
mHandler.sendMessageDelayed(msg, 3*DELAY_TIMES);
}
}
if (0 != (properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY)) {
Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support notify");
}
if ((0 != (properties & BluetoothGattCharacteristic.PROPERTY_WRITE))) {
Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support write");
if (gattCharacteristic.getUuid().toString().equals(LeXinUUID.WRITE_CHARA)) {
Message msg = new Message();
msg.what = MSG_WRITE_CHARA;
msg.obj = gattCharacteristic;
mHandler.sendMessageDelayed(msg, 2*DELAY_TIMES);
}
}
List gattDescriptors = gattCharacteristic.getDescriptors();
for (int k = 0; k < gattDescriptors.size(); k++) {
BluetoothGattDescriptor gattDescriptor = (BluetoothGattDescriptor)gattDescriptors.get(k);
Log.d(TAG, "gattDescriptors, descriptor uuid = " + gattDescriptor.getUuid());
// gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
// mBluetoothGatt.writeDescriptor(gattDescriptor);
}
}
}
Log.d(TAG, "----- parseServie end -----");
}
在解析的过程中,我们判断了characteristic的properties是否支持read、write、notify、indicate。解析结果如下:
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: ----- start parseServie -----
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 00001800-0000-1000-8000-00805f9b34fb
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb properties = 10
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a01-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a01-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a02-0000-1000-8000-00805f9b34fb properties = 10
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a02-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a02-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a04-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a04-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a03-0000-1000-8000-00805f9b34fb properties = 14
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a03-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a03-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 00001801-0000-1000-8000-00805f9b34fb
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a05-0000-1000-8000-00805f9b34fb properties = 34
03-22 21:39:10.795 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a05-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.795 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a05-0000-1000-8000-00805f9b34fb support indicate
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 0000fee7-0000-1000-8000-00805f9b34fb
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec8-0000-1000-8000-00805f9b34fb properties = 32
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec8-0000-1000-8000-00805f9b34fb support indicate
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec9-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec9-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec7-0000-1000-8000-00805f9b34fb properties = 8
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec7-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 0000180a-0000-1000-8000-00805f9b34fb
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a29-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a29-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a24-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a24-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a25-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a25-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a27-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a27-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a26-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a26-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a28-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a28-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a23-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a23-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a2a-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a2a-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a50-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a50-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 0000fee8-0000-1000-8000-00805f9b34fb
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 003784cf-f7e3-55b4-6c4c-9fd140100a16 properties = 16
03-22 21:39:10.800 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 003784cf-f7e3-55b4-6c4c-9fd140100a16 support notify
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002901-0000-1000-8000-00805f9b34fb
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 013784cf-f7e3-55b4-6c4c-9fd140100a16 properties = 4
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = d618d000-6000-1000-8000-000000000000
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d002-6000-1000-8000-000000000000 properties = 32
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d002-6000-1000-8000-000000000000 support indicate
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d001-6000-1000-8000-000000000000 properties = 8
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d001-6000-1000-8000-000000000000 support write
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: ----- parseServie end -----
我们根据上面的解析结果,选取了00002a50-0000-1000-8000-00805f9b34fb来做实验,在解析到该characteristic时,我们读取该属性值,代码看3.2部分代码块。在回调onCharacteristicRead()中添加如下的打印,
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicRead, characteristic = " + characteristic + ", status = " + status + ", value = " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0));
}
实验结果如下,说明我们收到了相应的回调,因为我们没有获取实际的协议,不知道这个值表示的实际含义。
03-24 21:13:09.645 20927-20938/com.atlas.devicefinder D/MainActivity: onCharacteristicRead, characteristic = android.bluetooth.BluetoothGattCharacteristic@2ac9086, status = 0, value = 1027
我们选取了"0000fec7-0000-1000-8000-00805f9b34fb"characteristic,在解析到该characteristic时,去读取该属性值。部分代码请查看3.2部分的代码段。
mHandler = new Handler(){
@NonNull
@Override
public void dispatchMessage(Message msg) {
Log.d(TAG, "dispatchMessage, msg = " + msg.what);
switch (msg.what) {
case MSG_WRITE_CHARA:
BluetoothGattCharacteristic gattCharacteristic2 = (BluetoothGattCharacteristic) msg.obj;
gattCharacteristic2.setValue("0");
mBluetoothGatt.writeCharacteristic(gattCharacteristic2);
break;
}
}
};
在回调onCharacteristicWrite()中添加如下的打印,
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicWrite, characteristic = " + characteristic + ", value = " + characteristic.getStringValue(0) + ", status = " + status);
}
实验结果如下,说明我们成功修改了该属性的值。
03-24 21:32:15.318 25167-25167/com.atlas.devicefinder D/MainActivity: dispatchMessage, msg = 2
03-24 21:32:15.385 25167-25366/com.atlas.devicefinder D/MainActivity: onCharacteristicWrite, characteristic = android.bluetooth.BluetoothGattCharacteristic@78102ba, value = 0, status = 0
我们选取了"d618d002-6000-1000-8000-000000000000"characteristic,其持有的descripotor UUID为"00002902-0000-1000-8000-00805f9b34fb"。
设置方法如下:
mHandler = new Handler(){
@NonNull
@Override
public void dispatchMessage(Message msg) {
Log.d(TAG, "dispatchMessage, msg = " + msg.what);
switch (msg.what) {
case MSG_INDICATE:
BluetoothGattCharacteristic gattCharacteristic3 = (BluetoothGattCharacteristic) msg.obj;
boolean ret =mBluetoothGatt.setCharacteristicNotification(gattCharacteristic3, true);
BluetoothGattDescriptor descriptor = gattCharacteristic3.getDescriptor(UUID.fromString(LeXinUUID.INDICATE_DES));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
break;
}
}
};
在onCharacteristicChanged ()和onDescriptorWrite()中添加如下打印。
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.d(TAG, "onCharacteristicChanged, characteristic = " + characteristic + ", value = " + characteristic.getValue());
}
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d(TAG, "onDescriptorWrite, descriptor = " + descriptor + ", status = " + status);
}
实际运行结果如下,仅有onDescriptorWrite()的打印,没有onCharateristicChanged()的打印,可能是因为我没有触发到该属性值发起改变的缘故(多次尝试体重测量都没有回调)。
设置notification的方法跟设置indication类似,只需要对对应的descriptor设置BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE。
综上,就是BLE Client端编程主要内容。
本文重点是开篇的BLE设备的结构,即characteristic是以service为基础的,descriptor是以characteristic为基础的,我们修改某个characteristic时,先要确定好service是那个。
如果想持续关注本博客内容,请扫描关注个人微信公众号,或者微信搜索:万物互联技术。