iOS 上的低功耗蓝牙数据传输

Bluetooth Low Energy data transmission on iOS

我最近在做一个使用低功耗蓝牙的项目。我实现了大部分通信协议,但是我开始担心,实际上我不知道数据传输是如何工作的,也不知道我实现的解决方案是否会以与所有设备相同的方式运行。

所以我主要关心的是当我收到来自 peripheral(_:didUpdateValueFor:error:) 的通知时收到的是什么数据块?它是否仅与协商的 MTU 大小一样大?或者 iOS 收到有关块大小的信息并在触发 peripheral(_:didUpdateValueFor:error:) 之前等待接收所有信息?

当外围设备发送块时,假设每个块 100 个字节,我可以假设我将始终在单个通知中收到 100 个字节吗?或者它可能是前一个块的最后 50 个字节和下一个块的前 50 个字节?这将非常棘手并且很难检测到我的框架的开始位置。

我试图在 Apple 文档中找到更多信息,但没有相关信息。

我的猜测是我总是收到一个单一的特征状态。因此,这意味着块取决于外围端的实现。但是,如果特性大于 MTU 大小怎么办?

首先,请记住,通过特征发送流数据并不是特征的设计目的。特性的要点是表示一些小的(~20 字节)信息,如当前电池电量、设备名称或当前心跳。这个想法是,只有当基础价值发生变化时,特征才会改变。它从未被设计成串行协议。因此,您的默认假设应该是,一切都由您来管理。

您向特征写入的数据不应多于您从 maximumWriteValueLength(for:) 获得的值。分块是你的工作。

您写入的每个单独的值都将原子地显示给接收者。请记住,这些是单独的值,而不是更大数据流中的块,因此重叠来自相同特征的值是没有意义的。 "Atomically" 表示全部到达或 none。因此,如果您的 MTU 可以处理 100 个字节,而您写入 100 个字节,则另一端将收到 100 个字节或什么也没有。

也就是说,BLE 中的错误检测非常少,您绝对可以丢弃数据包。由您来验证数据是否正确到达。

如果您能够针对 iOS 11+,请查看 L2CAP,它专为串行协议而不是使用 GATT 而设计。

如果您做不到,我建议您观看 WWDC 2013 Session 703,其中详细介绍了此用例。 (但是,我再也找不到 link 了。)