【问题标题】:Does CBCentralManager connect ever time out?CBCentralManager 连接是否超时?
【发布时间】:2016-11-24 10:18:22
【问题描述】:
我知道答案名义上是“否”,但我的意思是真的——如果应用程序进入后台(启用 BTLE 后台处理)怎么办? 24小时?应用更新?
在标题“重新连接到外围设备”下,Apple documentation 描述了一个重新连接工作流程,它首先尝试重新连接到通过retrievePeripheralsWithIdentifiers: 找到的先前配对的外围设备,但如果连接失败,则会再次开始扫描。如果没有正式的超时,你怎么知道何时放弃connect-ing 到以前找到的外围设备?如果您的想法是在您回到之前找到的 BTLE 设备时重新连接到它,而无需用户与您的应用进行交互,您如何知道何时开始/继续扫描?
此外,该页面下方的注释说,某些 BTLE 设备可能会在每次开机时为自己发明一个随机标识符,因此即使您从 retrievePeripheralsWithIdentifiers: 找到一些以前配对的外围设备,您也可能无法连接到他们,因为他们的名字已经改变。在实践中是否有任何 BTLE 设备可以做到这一点?这太疯狂了!
【问题讨论】:
标签:
ios
core-bluetooth
btle
【解决方案1】:
这是一个很难回答的问题。 CoreBluetooth 框架本身没有连接请求的官方超时。事实上,它会尽可能长时间地尝试连接外围设备。但那是多长时间?
好吧,不幸的是,这不是很明确的定义。当应用程序在前台时,您可以确信连接不会超时,但是一旦您在后台涉及连接,事情就不再那么有趣了。显然,就像您提到的那样,挂起的连接在手机重启后将不会保留,等等。这很好,因为没有用户会期望应用程序在重启后仍然运行。关于长时间运行的挂起连接,您会在 Apple 的文档中找到他们告诉您选择加入状态保存和恢复,以确保在应用程序暂停并最终终止时正确保留挂起的连接。如果它像宣传的那样工作会很好,但不幸的是它没有。经过多年的研究,我发现在 iOS 上获得可靠的后台挂起连接几乎是不可能的。我已经报告了很多关于这个主题的错误,但到目前为止还没有解决。
有几个问题我认为你应该特别注意:
如果在您的应用处于终止状态时发生蓝牙状态更改事件,状态保存和恢复将完全停止工作。这实质上意味着,如果蓝牙芯片因任何原因(例如通过切换蓝牙/飞行模式/等)重置,那么只要外围设备在范围内进行广告,核心蓝牙将永远不会重新启动您的应用程序。这样做的原因是因为每当蓝牙芯片重新启动时,您的应用程序设置的所有未决连接都将被清除。这样做的问题是您的应用程序将不会重新启动以收到此更改的通知,因此将永远不会恢复挂起的连接。所以你的应用程序会认为外围设备会连接,而实际上它们不会。对我来说,这是最严重的问题,仅此一项就使 CoreBluetooth 极其不可靠。
有时框架会“陷入”不良状态(可能是由于内部竞争条件或类似情况)。这可以随机发生,但您可以通过在 didFailToConnect 或 didDisconnect 回调中立即调用 connectPeripheral 来轻松重现此情况。当这种情况发生时,“连接状态”属性设置为“正在连接”,而实际上未设置挂起的连接。为了避免这种情况,我发现您应该在连接之前至少等待 20 毫秒左右,例如使用 dispatch_after 或其他东西。
框架内部使用 XPC 连接进行进程间通信,以传递蓝牙事件。在某些情况下,无论出于何种原因,这都会中断,并且连接将丢失。我不知道为什么会发生这种情况,但是一旦发生这种情况,状态保存就会停止工作,您必须手动重新启动应用程序才能从中恢复。有时我会设法在设备 sysdiagnose 日志中捕捉到这一点...
使用 iPhone 7 并同时拥有 Apple Watch(已与手机配对)将完全中断从锁定屏幕后面的所有重新连接,以防手表当前未连接(超出范围/飞行模式/电池电量低/或任何其他原因)。这特别糟糕,因为它是最近推出的!但看起来 Apple Watch 出于某种原因比其他蓝牙外围设备具有“优先级”。
这些都是我的想法,但还有其他问题。关于随机地址,这些外围设备通常使用所谓的“随机可解析”地址。这意味着它们看起来是随机的,但实际上可以使用通常在初始蓝牙绑定期间共享的 IRK(身份解析密钥)来解析它们。据我所知,使用完全随机地址的设备并不常见。