iOS 服务广告如何在后台工作?

How does iOS Service Advertising Work in the Background?

Apple 在 iOS 上进行后台 GATT 服务广告的专有技术如何运作?

根据 Apple 的文档,当使用 CoreBluetooth 实现 BLE 外围设备的 iOS 应用程序在后台运行时,服务 UUID 不再被公布,而是被放置在一个特殊的 "overflow area" 上:

Any service UUIDs contained in the value of the CBAdvertisementDataServiceUUIDsKey key that don’t fit in the allotted space go to a special “overflow” area. These services are discoverable only by an iOS device explicitly scanning for them. While your app is in the background, the local name isn’t advertised and all service UUIDs are in the overflow area. -- developer.apple.com

但这"overflow area"是什么?它是如何工作的?

I set up a bluetooth sniffer and captured the BLE data exchange, but failed to find any communication of this Service UUID. A second iOS device in the foreground was repeatedly able to successfully discover the service advertisement on the backgrounded iOS device, but the packet capture 从未记录过服务 UUID。

那么这是如何工作的?

如果我能弄清楚它是如何工作的,我想尝试对 Android 设备进行编程以使用相同的过程。

当至少有一个 iOS 应用程序在后台宣传 CoreBluetooth 服务时,溢出区是从 iOS 设备发出的制造商广告。它看起来像这样:

ff 4c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80

ff 表示制造商广告, 4c 00 字节对应 Apple 蓝牙 SIG 分配的制造商代码 0x004C。 01 将此标识为溢出区域广告。最后 16 个字节(128 位)是广告服务的散列位掩码。

您公布的每个服务 UUID 都会导致这 128 位中的一个位被设置为 1。服务 UUID 与其在此位掩码中设置的位位置之间存在一对一的映射。这在 iOS 台设备上是一致的。将服务 UUID 转换为位掩码中的位位置是一些专有的 Apple 哈希算法。

因为有大量可能的 128 位 UUID – 2^128(大约 10^38)– 多个服务 UUID 共享相同的位位置。

由于许多服务 UUID 共享溢出区域位掩码中的每个位位置,因此不可避免地会发生冲突。 iOS 将提供一个冲突但不同的服务 UUID 的扫描回调。这不会经常发生。但是程序员应该意识到,他们可能会扫描他们的服务,只是为了获得一个回调,以检测后台 iOS 设备广告完全不同的服务,恰好在溢出区域的位掩码中发生冲突。

有趣的是,可以操纵溢出区域,使两个后台 iOS 应用程序能够在后台交换数据。 See my blog post for more info.