You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

安卓Kotlin BLE开发:如何通过UUID识别设备可用服务与可读内容

BLE设备广播内容与特征数据识别实现方案(Kotlin安卓方向)

读取广播包内容(无需连接设备即可获取)

BLE设备的广播内容在扫描阶段就可以直接获取,不需要建立GATT连接,通过ScanCallback的回调参数即可解析:

private val bleScanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult?) {
        super.onScanResult(callbackType, result)
        result ?: return
        val scanRecord = result.scanRecord ?: return
        
        // 可直接获取的广播字段
        val deviceName = scanRecord.deviceName
        val rssi = result.rssi // 信号强度
        val broadcastServiceUuids = scanRecord.serviceUuids // 广播携带的服务UUID
        val rawBroadcastBytes = scanRecord.bytes // 广播原始字节数组
        
        // 打印示例
        val rawHex = rawBroadcastBytes.joinToString(" ") { "%02X".format(it) }
        Log.d("BLE广播", "设备名:$deviceName 信号强度:$rssi 原始广播数据:$rawHex")
    }
}

读取已连接设备的特征数据

建立GATT连接并发现服务后,先判断特征的可读权限,再执行读取操作,最后根据UUID类型解析数值:

第一步:判断特征可读权限并发起读取

// 遍历所有服务和特征
gatt.services.forEach { service ->
    service.characteristics.forEach { characteristic ->
        // 检查特征是否支持读取
        val canRead = (characteristic.properties and BluetoothGattCharacteristic.PROPERTY_READ) != 0
        if (canRead) {
            // 发起读取请求,注意不要并发发起多个读取请求,等上一个回调完成再发下一个
            gatt.readCharacteristic(characteristic)
        }
    }
}

第二步:在读取回调中解析数据

override fun onCharacteristicRead(
    gatt: BluetoothGatt?,
    characteristic: BluetoothGattCharacteristic?,
    status: Int
) {
    super.onCharacteristicRead(gatt, characteristic, status)
    if (status != BluetoothGatt.GATT_SUCCESS || characteristic == null) return
    
    val rawValue = characteristic.value
    // 标准UUID特征按照蓝牙联盟规范解析,厂商自定义UUID需对应厂商协议解析
    when (characteristic.uuid.toString()) {
        "00002a19-0000-1000-8000-00805f9b34fb" -> {
            // 电池电量特征,单字节0-100
            val batteryPercent = rawValue[0].toInt()
            Log.d("特征解析", "电池电量:$batteryPercent%")
        }
        "00002a2b-0000-1000-8000-00805f9b34fb" -> {
            // 当前时间特征,按蓝牙时间规范解析
            val year = (rawValue[1].toInt() shl 8) or rawValue[0].toInt()
            val month = rawValue[2].toInt()
            val day = rawValue[3].toInt()
            Log.d("特征解析", "当前时间:$year年$month月$day日")
        }
        else -> {
            // 未知特征先打印原始十六进制值
            val hexValue = rawValue.joinToString(" ") { "%02X".format(it) }
            Log.d("特征解析", "UUID:${characteristic.uuid} 原始值:$hexValue")
        }
    }
}

你提供的Gatt表快速识别

UUID前缀为0000xxxx-0000-1000-8000-00805f9b34fb的是蓝牙联盟定义的标准公开服务/特征,其他为厂商自定义私有内容:

  • 00001801服务:通用属性服务,对应00002a05特征为服务修改通知特征
  • d0611e78服务:厂商自定义私有服务,对应8667556c为私有特征,需设备厂商提供协议解析
  • 9fa480e0服务:厂商自定义私有服务,对应af0badb1为私有特征,需设备厂商提供协议解析
  • 0000180f服务:标准电池服务,对应00002a19为电池电量特征
  • 00001805服务:标准当前时间服务,对应00002a2b为当前时间特征、00002a0f为本地时间信息特征

注意事项

  • 安卓12及以上系统需要动态申请BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限才能执行扫描、连接、读特征操作
  • 不要同时发起多个GATT操作,所有读取、写入、通知操作都要等上一个操作的回调返回后再发起下一个,避免出现协议栈错误
  • 私有厂商UUID的特征如果没有对应协议文档,只能获取原始字节,无法直接解析为可读业务内容

内容的提问来源于stack exchange,提问作者Prabh Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 00:39:01