如何解析 Eddystone UID BLE 信标信息

问题描述

我正在尝试为 BLE Eddystone UID 数据包编写解析器,但不知道具体该怎么做。 我正在使用 Beacon Simulator App 广播 Eddystone UID 数据包,当我使用与扫描仪相同的应用程序在不同的手机上进行测试时,我可以看到第一台设备广播的 Eddystone UID 数据包。

我想编写一个示例应用程序来扫描 Eddystone UID 数据包。 我知道我必须使用 BluetoothLeScanner,并且在 onScanResultScanCallback 中,我可以获得与 BLE(低功耗蓝牙)兼容的所有蓝牙设备。

但问题是我能够从 ScanResult提取设备 mac、设备名称,并且可以验证我是否能够听到我的蓝牙耳机和扬声器的声音,但我不确定我将如何获得 {{1 }} 和 namespace 的 Eddystone UID,我无法在 instance 中看到任何此类变量,这对我有帮助。

任何人都可以向我指出有关如何执行此操作的任何片段或任何代码。我不想使用任何第三方库进行扫描,在 Kotlin 或 Java 中简单明了。 Kotlin 是首选,但 java 也不错,我知道这两种语言。

解决方法

Eddystone UID:具有 10 字节命名空间组件和 6 字节实例组件的唯一静态 ID。 在 onScanResult 中,您可以提取如下所示的 Eddystone uid 数据包

override fun onScanResult(callbackType: Int,result: ScanResult) {
            val scanRecord = result.scanRecord
            if (scanRecord != null) {
                val serviceUuids = scanRecord.serviceUuids
                if (serviceUuids != null && serviceUuids.size > 0 && serviceUuids.contains(
                        eddystoneServiceId
                    )
                ) {
                    val serviceData = scanRecord.getServiceData(eddystoneServiceId)
                    if (serviceData != null && serviceData.size > 18) {
                        val eddystoneUUID =
                            Utils.toHexString(Arrays.copyOfRange(serviceData,2,18))
                        val namespace = String(eddystoneUUID.toCharArray().sliceArray(0..19))
                        val instance = String(
                            eddystoneUUID.toCharArray()
                                .sliceArray(20 until eddystoneUUID.toCharArray().size)
                        )

                        Log.e("DINKAR","Namespace:$namespace Instance:$instance")
                    }
                }
               
            }
        }

scanRecord:广告和扫描响应的组合

serviceUuids:广告中用于识别蓝牙 GATT 服务的服务 UUID 列表。

eddystoneServiceId : Eddystone UID 的服务 UUID,即“0000FEAA-0000–1000–8000–00805F9B34FB”

serviceData:与 serviceUuid 关联的服务数据字节数组,在我们的例子中是 eddystoneServiceId

eddystoneUID 数据包信息在 serviceData 中从索引 2 到 18,我们需要使用实用方法将此字节数组转换为十六进制字符串。

namespace 是 10 个字节,从 eddystoneUID 的 20 个字符开始

instanceId 为 6 个字节,即 eddystoneUID 的其余 12 个字符

向您展示如何将字节数组转换为十六进制字符串的示例

   private val HEX = "0123456789ABCDEF".toCharArray()
fun toHexString(bytes: ByteArray): String {
    if (bytes.isEmpty()) {
        return ""
    }
    val hexChars = CharArray(bytes.size * 2)
    for (j in bytes.indices) {
        val v = (bytes[j].toInt() and 0xFF)
        hexChars[j * 2] = HEX[v ushr 4]
        hexChars[j * 2 + 1] = HEX[v and 0x0F]
    }
    return String(hexChars)
}

我写了一篇关于解析 Eddystone UID 和 iBeacon 的博客,你可以参考here

此外,您可以参考完整的工作示例应用程序来扫描 Eddystone UID、iBeacon 和普通蓝牙外围设备 here