Android BLE 开发指南二:广播数据解析

广播数据结构

BLE 外设开始工作时,会发出广播让中心设备发现,广播的数据包中带有外设的相关信息,比如设备的MAC地址,名字,Service 列表的 UUID 等等。

广播包的数据结构都是固定的,按照蓝牙相关规范规定好的。
每个包都是 31 字节,数据包中分为有效数据(significant)和无效数据(non-significant)两部分。

有效数据部分: 包含若干个广播数据单元 AD Structure。如图中所示,AD Structure 的组成是:第一个字节是长度值 Len,表示接下来的 Len 个字节是数据部分。数据部分的第一个字节表示数据的类型 AD Type,剩下的 Len - 1 个字节是真正的数据 AD data。其中 AD type 非常关键,决定了 AD Data 的数据代表的是什么,怎么解析。

无效数据部分: 因为广播包的长度必须是 31 个 byte,如果有效数据部分不到 31 自己,剩下的就用 0 补全。这部分的数据是无效的,解释的时候,忽略即可。
ble_ad_structure

AD Type 类型

AD Type 包括如下类型:

Flags: TYPE = 0x01 这个数据用来标识设备 LE 物理连接的功能。DATA 是 0 到多个字节的 Flag 值,每个 bit 上用 0 或者 1 来表示是否为 True。如果有任何一个 bit 不为 0,并且广播包是可连接的,就必须包含此数据。各 bit 的定义如下:

bit 0: LE 有限发现模式
bit 1: LE 普通发现模式
bit 2: 不支持 BR/EDR
bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR
bit 4: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
bit 5..7: 预留

Service UUID 广播数据中一般都会把设备支持的 GATT Service 广播出来,用来告诉外面本设备所支持的 Service。有三种类型的 UUID:16 bit, 32bit, 128 bit。广播中,每种类型类型有有两个类别:完整和非完整的。这样就共有 6 种 AD Type。

非完整的 16 bit UUID 列表: TYPE = 0x02;
完整的 16 bit UUID 列表: TYPE = 0x03;
非完整的 32 bit UUID 列表: TYPE = 0x04;
完整的 32 bit UUID 列表: TYPE = 0x05;
非完整的 128 bit UUID 列表: TYPE = 0x06;
完整的 128 bit UUID 列表: TYPE = 0x07;

Local Name 设备名字 DATA 是名字的字符串。Local Name 可以是设备的全名,也可以是设备名字的缩写,其中缩写必须是全名的前面的若干字符。

设备全名: TYPE = 0x08
设备简称: TYPE = 0x09

TX Power Level: TYPE = 0x0A 表示设备发送广播包的信号强度。DATA 部分是一个字节,表示 -127 到 + 127 dBm。

带外安全管理(Security Manager Out of Band):TYPE = 0x11 :DATA 也是 Flag,每个 bit 表示一个功能:

bit 0: OOB Flag,0 表示没有 OOB 数据,1 表示有
bit 1: 支持 LE
bit 2: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
bit 3: 地址类型,0 表示公开地址,1 表示随机地址

外设(Slave)连接间隔范围:TYPE = 0x12 :数据中定义了 Slave 最大和最小连接间隔,数据包含 4 个字节:

前 2 字节:定义最小连接间隔,取值范围:0x0006 ~ 0x0C80,而 0xFFFF 表示未定义;
后 2 字节:定义最大连接间隔,同上,不过需要保证最大连接间隔大于或者等于最小连接间隔。

服务搜寻:外围设备可以要请中心设备提供相应的 Service。其数据定义和前面的 Service UUID 类似:

16 bit UUID 列表: TYPE = 0x14
32 bit UUID 列表: TYPE = 0x??
128 bit UUID 列表: TYPE = 0x15

Service Data: Service 对应的数据。

16 bit UUID Service: TYPE = 0x16, 前 2 字节是 UUID,后面是 Service 的数据;
32 bit UUID Service: TYPE = 0x??, 前 4 字节是 UUID,后面是 Service 的数据;
128 bit UUID Service: TYPE = 0x??, 前 16 字节是 UUID,后面是 Service 的数据;

公开目标地址:TYPE = 0x17,表示希望这个广播包被指定的目标设备处理,此设备绑定了公开地址,DATA 是目标地址列表,每个地址 6 字节。

随机目标地址:TYPE = 0x18,定义和前一个类似,表示希望这个广播包被指定的目标设备处理,此设备绑定了随机地址,DATA 是目标地址列表,每个地址 6 字节。

Appearance:TYPE = 0x19,DATA 是表示了设备的外观。

厂商自定义数据: TYPE = 0xFF: 厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义。

这里列举了部分常见的数据,还有一些其他的数据。

广播数据解析

在Android中,扫描蓝牙设备有两套api,一套是Android4.3上面的,扫描的广播数据需要自己解析;另一套是Android5.0上面的,扫描的广播数据,系统会帮我们解析好。
下面是Android4.3上面的开启扫描代码:

	//扫描结果回调
    val leScanCallback = object : BluetoothAdapter.LeScanCallback {
        override fun onLeScan(device: BluetoothDevice, rssi: Int, scanRecord: ByteArray) {
			//回调在子线程
			ParseBluetoothAdData.parse(scanRecord)//解析广播数据
        }
    }
	val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
	if (bluetoothAdapter.isEnabled) {//蓝牙为打开状态
	    bluetoothAdapter.startLeScan(leScanCallback)//开始扫描,传入回调接口
	}

下面是解析广播的代码,这里只解析了UUID,厂商数据和设备名字:

object ParseBluetoothAdData {
    fun parse(bytes: ByteArray): AdData {
        val baseUuid = "%08X-0000-1000-8000-00805F9B34FB"
        val uuidS = ArrayList<UUID>()
        var manufacturerByte: ByteArray? = null
        var name: String? = null
        val buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN)
        while (buffer.remaining() > 2) {
            var length = buffer.get().toInt() and 0xff
            if (length == 0) {
                break
            }
            val type = buffer.get().toInt() and 0xff
            length--
            when (type) {
                0x01 -> {
                    buffer.position(buffer.position() + length)
                }
                0x02, 0x03, 0x14 -> {
                    while (length >= 2) {
                        uuidS.add(UUID.fromString(String.format(baseUuid, buffer.short)))
                        length -= 2
                    }
                }
                0x04, 0x05 -> {
                    while (length >= 4) {
                        uuidS.add(UUID.fromString(String.format(baseUuid, buffer.int)))
                        length -= 4
                    }
                }
                0x06, 0x07, 0x15 -> {
                    while (length >= 16) {
                        val lsb = buffer.long
                        val msb = buffer.long
                        uuidS.add(UUID(msb, lsb))
                        length -= 16
                    }
                }
                0xff -> {//厂商自定义数据
                    manufacturerByte = ByteArray(length)
                    buffer.get(manufacturerByte, 0, length)
                }
                0x09, 0x08 -> {//全名,简短名
                    val byteArray = ByteArray(length)
                    buffer.get(byteArray)
                    name = String(byteArray)
                }
                else -> {
                    buffer.position(buffer.position() + length)
                }
            }
        }
        return AdData(uuidS, manufacturerByte, name)
    }

    class AdData(val UUIDs: ArrayList<UUID>, val manufacturerByte: ByteArray?, val name: String?)
}

以上内容摘自

BLE 广播数据解析

### 下载 Popper.min.js 文件的方法 对于希望获取 `popper.min.js` 的开发者来说,可以通过多种方式来实现这一目标。通常情况下,推荐通过官方渠道或可靠的分发网络 (CDN) 来获得最新的稳定版文件。 #### 使用 CDN 获取 Popper.min.js 最简单的方式之一是从流行的 CDN 中加载所需的 JavaScript 库。这不仅简化了集成过程,还可能提高性能,因为许多用户已经缓存了来自这些服务提供商的内容。例如: ```html <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2/dist/umd/popper.min.js"></script> ``` 这种方式不需要手动下载文件到本地服务器;只需将上述 `<script>` 标签添加至 HTML 文档中的适当位置即可立即使用 Popper 功能[^1]。 #### 从 npm 或 yarn 安装 如果项目采用模块化构建工具链,则可以直接利用包管理器如 npm 或 Yarn 进行安装。命令如下所示: ```bash npm install @popperjs/core # 或者 yarn add @popperjs/core ``` 之后可以根据具体需求引入特定功能模块,而不是整个库,从而减少打包后的体积并优化加载速度[^2]。 #### 访问 GitHub 发布页面下载压缩包 另一种方法是访问 Popper.js 的 [GitHub Releases](https://github.com/popperjs/popper-core/releases) 页面,在这里可以选择不同版本的 tarball 或 zip 归档进行下载解压操作。这种方法适合那些偏好离线工作环境或是想要定制编译选项的人群[^3]。 #### 手动克隆仓库 最后一种较为少见但也可行的办法便是直接克隆完整的 Git 存储库副本。这样可以获得开发分支以及历史记录等更多信息,适用于贡献代码或者深入学习内部机制的情况。 ```bash git clone https://github.com/popperjs/popper-core.git cd popper-core ``` 完成以上任一途径后便能成功取得所需版本的 Popper.min.js 文件,并将其应用于个人项目之中[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值