CBCentralManager 连接是否超时?

Does CBCentralManager connect ever time out?

我知道答案名义上是 "no",但我的意思是 真的 ——如果应用程序进入后台(启用​​ BTLE 后台处理)怎么办? 24小时?跨应用更新?

在标题 "Reconnecting to Peripherals" 下,此 Apple documentation 描述了一个重新连接工作流程,该工作流程首先尝试重新连接到之前通过 retrievePeripheralsWithIdentifiers: 找到的已配对外围设备,但如果连接失败则再次开始扫描.如果没有正式超时,您如何知道何时放弃 connect-ing 到先前找到的外围设备?你怎么知道什么时候 start/keep 扫描,如果你的想法是 re-connect 到以前找到的 BTLE 设备,只要你回到它附近,而用户不必与你的应用程序交互?

此外,该页面下方的一条注释说,某些 BTLE 设备可能会在每次开机时为自己发明一个随机标识符,因此即使您从 retrievePeripheralsWithIdentifiers: 找到了一些以前配对的外围设备,您也可能由于他们的名称已更改,因此无法连接到他们。有没有任何 BTLE 设备在实践中这样做?太疯狂了!

这个问题很难回答。 CoreBluetooth 框架本身没有关于连接请求的正式超时。事实上,它会尽可能长时间地尝试连接外围设备。但那有多长?

嗯,不幸的是,这不是一个非常明确的定义。当应用程序处于前台时,您可以非常确信连接不会超时,但是一旦您在后台涉及连接,事情就不再那么有趣了。显然,就像您提到的那样,挂起的连接在 phone 重启后不会保留,等等。这很好,因为没有用户会期望该应用程序在重启后仍然是 运行。关于长 运行 挂起连接,您会在 Apple 的文档中找到他们告诉您选择加入状态保存和恢复,以确保在应用程序暂停并最终终止时正确保留挂起连接。如果它能像宣传的那样工作,那会很好,但不幸的是它没有。经过多年的工作,我发现几乎不可能在 iOS 上获得可靠的后台挂起连接。我已经报告了很多关于这个主题的错误,但到目前为止 none 已经解决了。

我觉得有几个问题需要特别注意:

  1. 如果您的应用程序处于终止状态时发生蓝牙状态更改事件,状态保存和恢复将完全停止工作。这实质上意味着,如果蓝牙芯片因任何原因被重置(例如通过切换 bluetooth/flight mode/etc..),那么只要外围设备在范围内进行广告,您的应用程序将永远不会被 Core Bluetooth 再次重新启动。这是因为只要蓝牙芯片重启,您的应用程序设置的所有挂起连接都将被清除。这样做的问题是您的应用程序不会重新启动以收到此更改的通知,因此挂起的连接将永远不会恢复。因此,您的应用会认为外围设备会连接,而实际上它们不会。对我来说,这是最严重的问题,仅此一项就使 CoreBluetooth 极其不可靠。

  2. 有时框架会“卡住”在一个糟糕的状态(可能是由于内部竞争条件或类似情况)。这可能是随机发生的,但是您可以通过在 didFailToConnect 或 didDisconnect 回调中立即调用 connectPeripheral 来很容易地重现它。当这种情况发生时,“连接状态”属性 被设置为“正在连接”,而实际上未设置挂起的连接。为了避免这种情况,我发现您应该在连接之前至少等待 20 毫秒左右,例如使用 dispatch_after 或其他东西。

  3. 该框架在内部使用 XPC 连接进行进程间通信以传递蓝牙事件。在某些情况下,无论出于何种原因,这都会中断并且连接会丢失。我不知道为什么会发生这种情况,但只要发生这种情况,状态保存就会停止工作,您将必须手动重新启动应用程序才能从中恢复。有时我设法在设备 sysdiagnose 日志中捕捉到这个...

  4. 使用 iPhone 7 并同时拥有 Apple Watch(与 phone 配对)将完全中断锁屏后的所有重新连接,以防 Watch当前未连接(出于 range/flight mode/low battery/or 任何其他原因)。这是特别糟糕的,因为它是最近推出的!但看起来 Apple Watch 出于某种原因 "priority" 优于其他蓝牙外围设备。

这些是我的想法,但还有其他问题。关于随机地址,这些外围设备通常使用所谓的“随机可解析”地址。这意味着它们看起来是随机的,但实际上它们可以使用通常在初始蓝牙绑定期间共享的 IRK(身份解析密钥)来解析。据我所知,使用完全随机地址的设备并不常见。