You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android应用中如何获取BLE智能手环数据?onServicesDiscovered后不知如何操作

从BLE手环获取数据的后续步骤

嘿,我来帮你理清楚onServicesDiscovered回调之后该怎么操作,这可是Android BLE开发里的关键节点哦!

当回调返回GATT_SUCCESS时,说明你已经成功扫描到手环提供的所有BLE服务和特征了。接下来按这几步走就能拿到数据:

1. 定位目标服务与特征

BLE设备的每个服务、特征都有唯一的UUID标识,你得先确定手环对应数据(比如心率、步数)的目标UUID——这个可以从手环的开发者文档里找,或者用BLE调试工具(比如nRF Connect)扫描手环获取。

比如心率服务的标准UUID是0000180d-0000-1000-8000-00805f9b34fb,对应的心率测量特征UUID是00002a37-0000-1000-8000-00805f9b34fb。你可以在循环里加判断来匹配这些UUID:

@Override 
public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
    super.onServicesDiscovered(gatt, status); 
    if (status == BluetoothGatt.GATT_SUCCESS) { 
        // 替换成你手环的目标服务UUID
        String targetServiceUuid = "0000180d-0000-1000-8000-00805f9b34fb";
        // 替换成你要获取数据的特征UUID
        String targetCharUuid = "00002a37-0000-1000-8000-00805f9b34fb";

        for (BluetoothGattService service : gatt.getServices()) { 
            Log.w("Service", service.getUuid().toString()); 
            if (service.getUuid().toString().equals(targetServiceUuid)) {
                // 找到目标服务,遍历它的特征
                for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) { 
                    Log.w("Characteristic", characteristic.getUuid().toString());
                    if (characteristic.getUuid().toString().equals(targetCharUuid)) {
                        // 找到目标特征,接下来根据属性处理
                        handleTargetCharacteristic(gatt, characteristic);
                        break;
                    }
                }
                break;
            }
        }
    } 
}

2. 根据特征属性选择数据获取方式

BLE特征有不同的属性(读取、通知、指示等),手环的实时数据一般用通知推送,静态数据(比如设备信息)可能用读取

情况A:特征支持通知(实时数据场景)

这是手环推送数据最常用的方式,你需要开启通知并配置描述符:

private void handleTargetCharacteristic(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    // 检查特征是否支持通知
    if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
        // 开启特征通知
        gatt.setCharacteristicNotification(characteristic, true);
        // 获取Client Characteristic Configuration描述符(固定UUID)
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
        );
        if (descriptor != null) {
            // 设置为启用通知
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            gatt.writeDescriptor(descriptor);
        }
    }
}

然后在BluetoothGattCallback中重写onCharacteristicChanged方法接收推送的数据:

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    super.onCharacteristicChanged(gatt, characteristic);
    // 获取手环发送的原始字节数据
    byte[] data = characteristic.getValue();
    // 根据手环的协议解析字节数组,转换成你需要的数据(比如心率)
    int heartRate = parseHeartRateData(data);
    Log.w("HeartRate", "当前心率:" + heartRate);
}

// 示例:解析标准心率数据
private int parseHeartRateData(byte[] data) {
    if (data == null || data.length == 0) return 0;
    // 第一个字节是标志位,判断心率格式
    int flags = data[0];
    boolean isUint16 = (flags & 0x01) != 0;
    return isUint16 ? 
        (data[1] & 0xFF) | ((data[2] & 0xFF) << 8) : 
        data[1] & 0xFF;
}

情况B:特征支持读取(静态数据场景)

如果是读取静态数据,直接调用读取方法即可:

private void handleTargetCharacteristic(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) != 0) {
        gatt.readCharacteristic(characteristic);
    }
}

然后在onCharacteristicRead回调里处理结果:

@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    super.onCharacteristicRead(gatt, characteristic, status);
    if (status == BluetoothGatt.GATT_SUCCESS) {
        byte[] data = characteristic.getValue();
        // 解析数据,比如设备名称
        String deviceName = new String(data);
        Log.w("DeviceInfo", "设备名称:" + deviceName);
    }
}

关键提醒

  • 一定要参考手环的官方开发文档,不同厂商的BLE数据协议可能有差异,解析逻辑要对应调整。
  • BLE操作要注意线程安全,建议在主线程之外处理(比如用Handler或者协程)。
  • 用完BluetoothGatt后记得调用close()释放资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Ovidiu Podina

火山引擎 最新活动