iOS 在来自外围设备的传入 BLE 连接时停止唤醒应用程序

iOS stops waking up the app upon incoming BLE connection from peripheral

我们有一个 BLE 外围设备,每小时连接到 phone 并传递一些数据。以下是该过程的工作原理:

中使用键 UIApplicationLaunchOptionsBluetoothCentralsKey 启动
  1. application(didFinishLaunchingWithOptions launchOptions) 应用程序使用传递给它的 ID 重新初始化 CBCentralManager。
  2. 然后它通过常规恢复周期并从 BLE 外设读取数据。
  3. 对云中的服务执行 REST 请求。

假设应用程序在 phone 重启后至少启动了一次,几天内一切正常(如果应用程序不是 运行 或被强制内存不足,iOS 正常再次启动它,假设用户没有手动强制关闭)。

但是每隔几天 iOS 当有来自 BLE 设备的传入请求时停止唤醒应用程序。如果用户重新启动应用程序,几天后一切正常,然后再次停止。鉴于我们产品的性质,让我们的应用程序/外围设备以尽可能最可靠的方式协同工作至关重要。

关于为什么会发生的理论:
(经过仔细检查,他们都被解雇了)

关于正在发生的事情以及为什么 iOS 停止通知应用有关传入 BLE 连接的任何想法?

其中一个问题是我们无法弄清楚如何可靠地重现该问题,因此我们也将不胜感激任何建议!

谢谢!


更新 1: 下面是我们如何初始化 CBCentralManager:

self.centralManager = CBCentralManager(delegate: self, queue: nil, options: [
    CBCentralManagerOptionRestoreIdentifierKey : MyCentralManagerID,
    CBCentralManagerOptionShowPowerAlertKey : 0])

我看到一些建议队列参数不应该为零。鉴于我无法可靠地重现问题,在我可以自信地观察其影响之前,我犹豫是否要进行更改。

首先我想说我已经使用 CoreBluetooth 很长时间了,据我所知,CoreBluetooth 状态保存和恢复根本无法可靠地工作。您可以让它正常工作 "ok",但除非 Apple 某天修复它,否则您永远无法让它可靠地重新连接。

导致此功能无法正常工作的错误太多,但我会给您一个我认为会导致您出现问题的错误:

如果事件源自您正在与之通信的外围配件,例如 connect/disconnect 事件和特征通知,则状态恢复只会因蓝牙相关 activity 重新启动您的应用程序。对于其他事件,最重要的一般蓝牙状态更改事件,您的应用程序将不会重新启动并收到通知。之所以如此糟糕,是因为所有蓝牙状态更改事件都会取消所有挂起的或当前的连接,这意味着挂起的连接将被丢弃,您的应用程序将不会收到通知。这实际上意味着您的应用程序仍然认为连接仍在挂起,而实际上它们并非挂起。由于此时您的应用程序已终止,因此再次唤醒它的唯一方法是让用户再次手动启动它(或者为此目的“破解”其他后台模式,这也不是很可靠)。

如果用户切换飞行模式、切换蓝牙、重启 iOS 设备,或任何其他导致状态变化的未定义原因,就会发生这种情况……

但这只是一个错误。还有许多其他问题,例如 XPC 连接在不同时间无缘无故地中断。我还注意到挂起的连接可以进入“边缘状态”模式,在这种模式下外围状态被设置为正在连接,但实际上它永远不会连接,除非你循环连接状态。

无论如何,我很遗憾地说出来,但是如果你正在开发一个必须依赖于在后台重新连接的外围设备的应用程序,那么我不建议这样做。你会感到沮丧。我可能会写一篇关于 Core Bluetooth 中 Apple 不想修复的所有错误的文章。更奇怪的是,您可以很容易地通过一个应用程序在设备上全局破坏​​蓝牙连接,这样在设备重新启动之前,任何应用程序都无法使用蓝牙。这非常糟糕,因为它违背了 Apple 自己的沙盒原则。