核心蓝牙状态保存和恢复不起作用,无法将应用程序重新启动到后台。

15

我正在尝试使核心蓝牙即使应用未运行也能唤醒它。

正如苹果所述,“由于状态保存和恢复内置于Core Bluetooth中,因此您的应用程序可以选择加入此功能,请求系统保留您的应用程序中央和外围管理器的状态,并继续代表它们执行某些与蓝牙相关的任务,即使您的应用程序不再运行。当其中一个任务完成时,系统会将您的应用程序重新启动到后台,并给您的应用程序机会恢复其状态并适当处理事件。”

我添加了以下代码来选择加入此功能:

 myCentralManager =
        [[CBCentralManager alloc] initWithDelegate:self queue:nil
         options:@{ CBCentralManagerOptionRestoreIdentifierKey:
         @"myCentralManagerIdentifier" }];

但是当应用程序被唤醒时,回调函数从未触发。

-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
}

-(void)centralManager:(CBCentralManager *)central
      willRestoreState:(NSDictionary *)state {
}

这两个从未被调用。

我正在测试这个唤醒函数的方法:

  1. 在info.plist中将“蓝牙中心”添加到后台模式,以使BLE在后台运行。

  2. 在我的iPhone No.1上启动centralManager并开始扫描。

  3. 按Home键退出应用,在内存繁重的游戏中玩一会儿,在调试日志中我会看到:"因内存压力而终止。进程以退出代码0结束"。这是为了模拟iOS系统由于内存压力而终止后台应用。

  4. 在另外一个iPhone No.2上启动一个信标并开始广播。

  5. 结果:那些重新启动回调从未被调用。

有什么想法为什么这不起作用吗?如果这是API问题,是否有其他方法可以在您的手机接近BLE信标时将应用程序重新启动到后台与BLE连接?我已经尝试使用ibeacon唤醒应用程序,但核心蓝牙中央管理器不允许您在后台连接到ibeacon。

谢谢!

3个回答

14
点击主页按钮将应用程序发送到后台时,它会被暂停,并且可以处理蓝牙代理并在后台运行10秒钟。此功能仅通过“在info.plist中添加蓝牙中央后台模式”即可实现,不使用状态保存和恢复。
如果IOS由于内存压力而终止您的应用程序,则无法再处理蓝牙代理。在这种情况下,如果您使用了状态保存和恢复,则可以重新启动应用程序以在后台运行,但也仅限于10秒钟。10秒后,它将转换为暂停状态。只有在这种情况下,CBCentralManager的willRestoreState才会被触发。
您可以添加代码
kill(getpid(), SIGKILL);
到按钮操作中,当单击该按钮时,您的应用程序会像被内存压力杀死一样被IOS终止,然后willRestoreState将被触发。
祝您好运。

1
有人验证过这个方法在代码中是否真正有效吗?如果是的话,这种方法比使用典型的BackgroundKiller应用程序要快得多。 - Etan
2
@Etan 这个真的有效!应用程序不应连接到XCode,因为这会破坏信号处理。 - allprog
1
@Etan 我已经使用kill测试了流程并使我的应用程序工作,但它似乎与iOS自然运行时不同。感谢您提到BackgroundKiller应用程序的想法,我认为我需要使用它来进行真正的测试。 - Michael Ozeryansky
1
@Michael Ozeryansky:正如Roy Zhang在2014年回答的那样,可能是行为在此期间发生了变化。同样,由于现代iOS硬件具有更多的RAM,BackgroundKiller应用程序可能需要更长时间或工作得更差。 - Etan
1
据我所知,您可以通过按住电源按钮直到出现“滑动关闭”的提示,然后再按住主页按钮直到返回主屏幕来模拟操作系统由于内存压力而杀死应用程序的情况。 - Pellet

4
我也遇到了已知服务UUID的外设背景扫描问题。这可能是iOS中的一个bug。我发现当iOS发现外设时,它会重新启动应用程序,可以通过在XCode的设备管理器中查看控制台输出来看到这一点。虽然调用了 didFinishLaunchingWithOptions 委托,但对 CBCentralManager 的 willRestoreState 委托的调用被延迟,直到用户手动将应用程序带到前台。
似乎主线程上的事件循环没有运行,即使应用程序已经启动。例如,当添加以下代码时:
dispatch_async(dispatch_get_main_queue(), ^{
  NSLog(@"Hello from the main thread");
});

对于didFinishLaunchingWithOptions代理方法,只有当应用程序进入前台时,消息才会在调试控制台中显示。

我的解决方法是使用运行在单独线程上的自定义队列,而不是在创建CBCentralManager时传递queue:nil。这样,在应用程序仍处于后台时,代理方法就会被调用。


1
你如何处理这个问题?我也遇到了同样的问题,我无法在后台调用委托方法。 - Solid Soft

4

CoreBluetooth 状态恢复仅适用于连接和外围事件。仅依靠扫描目前不受支持。


谢谢tdevoy,有没有通过BLE重新启动应用程序的解决方法? - woof
1
嗨@tdevoy,您能否请详细说明一下外围事件。 - raghul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接