
本文详解如何在 kotlin 移动应用中,不依赖厂商私有 sdk,而是基于 bluetooth low energy(ble)标准协议,统一接入 mi band、huawei watch 等主流健身追踪器并读取心率等传感器数据。核心在于识别标准化服务与特征 uuid,并正确解析原始字节流。
本文详解如何在 kotlin 移动应用中,不依赖厂商私有 sdk,而是基于 bluetooth low energy(ble)标准协议,统一接入 mi band、huawei watch 等主流健身追踪器并读取心率等传感器数据。核心在于识别标准化服务与特征 uuid,并正确解析原始字节流。
在 Android(Kotlin)开发中,若需从不同品牌的健身追踪器(如 Mi Band、Huawei Watch、Amazfit 等)统一获取心率、步数等健康数据,不存在“一键兼容”的官方通用 API——但存在一套跨厂商的底层通用方案:基于 Bluetooth SIG 官方 BLE 标准协议的自主对接。该方案不依赖厂商 SDK,而是直接通过 Android 的 BluetoothGatt API 与设备建立低功耗蓝牙连接,发现服务、读取/订阅特征值,并按规范解析二进制数据。
? 第一步:扫描并连接 BLE 设备
使用 BluetoothAdapter 扫描周边设备,筛选出目标健身追踪器(可通过设备名称或 MAC 地址识别),然后调用 device.connectGatt() 建立 GATT 连接:
val gatt = device.connectGatt(context, false, gattCallback)
确保在 BluetoothGattCallback 中监听 onConnectionStateChange(),确认连接成功后再执行服务发现。
⚙️ 第二步:发现服务与特征(关键标准化步骤)
连接成功后,调用 gatt.discoverServices()。待 onServicesDiscovered() 回调触发,遍历所有服务:
gatt.services.forEach { service ->
Log.d("BLE", "Service UUID: ${service.uuid}")
service.characteristics.forEach { characteristic ->
Log.d("BLE", " → Char UUID: ${characteristic.uuid}")
}
}- 心率服务(Heart Rate Service, HRS) 的标准 UUID 为 0000180D-0000-1000-8000-00805F9B34FB(即 0x180D)。
- 其核心特征 Heart Rate Measurement 的 UUID 为 00002A37-0000-1000-8000-00805F9B34FB(即 0x2A37)。
✅ 提示:UUID 可查 Bluetooth SIG Assigned Numbers 文档;服务详细行为请查阅 Bluetooth SIG Spec - Heart Rate Service。
? 第三步:启用通知并解析心率数据
HRS 要求启用通知(NOTIFY) 而非简单读取(READ),因为心率是持续上报的动态数据:
val hrChar = service.getCharacteristic(UUID.fromString("00002A37-0000-1000-8000-00805F9B34FB"))
gatt.setCharacteristicNotification(hrChar, true)
// 启用 Client Characteristic Configuration Descriptor (CCCD)
val cccd = hrChar.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805F9B34FB"))
cccd.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
gatt.writeDescriptor(cccd)当 onCharacteristicChanged() 触发时,characteristic.value 是一个 ByteArray,需按 HRS 规范 解析:
fun parseHeartRate(value: ByteArray): Int? {
val flags = value[0].toInt() and 0xFF
var offset = 1
return if (flags and 0x01 != 0) { // HR value in 16-bit format?
((value[offset + 1].toInt() and 0xFF) shl 8) or (value[offset].toInt() and 0xFF)
} else { // 8-bit format
value[offset].toInt() and 0xFF
}
}⚠️ 注意事项与现实挑战
- 厂商定制服务不可避免:Mi Band 步数、睡眠等数据通常使用私有服务(如 0xFEE0)和特征(如 0x0007),无法通过标准 HRS 获取。此时需参考开源项目逆向分析(如 miband-android)。
- 权限与后台限制:Android 12+ 需声明 BLUETOOTH_SCAN、BLUETOOTH_CONNECT 动态权限;后台 BLE 操作受严格限制,建议前台服务或用户交互触发。
- 设备兼容性差异:部分设备需配对(Bonding)后才开放全部服务;某些型号需先写入特定控制特征(如启动传感器)才能收到通知。
- 调试建议:使用 nRF Connect App(Nordic)手动探索设备服务结构,验证 UUID 与数据格式,再迁移至 Kotlin 实现。
✅ 总结
真正的“通用”不在于单个 API,而在于掌握 BLE 协议栈的通用工作流:连接 → 发现服务 → 匹配标准 UUID → 启用通知 → 按规范解析。标准服务(如 HRS、Battery Service)可覆盖 70%+ 基础健康数据;非标数据则需结合社区逆向成果与厂商文档补充。坚持这一路径,你将摆脱对 Mi Fit、Huawei Health 等封闭 SDK 的依赖,构建真正自主可控的健康数据接入能力。

















