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

时间:2013-12-11 20:53:12

标签: ios bluetooth-lowenergy core-bluetooth cbcentralmanager state-restoration

即使它没有运行,我也试图让核心蓝牙唤醒应用程序。

正如Apple所说,“由于状态保存和恢复是内置于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中的后台模式中添加了“bluetooth central”,因此BLE在后台运行。

  2. 在我的iphone No.1中启动centralManager。开始扫描。

  3. 按回家退出,玩一些内存沉重的游戏,在调试日志中我会看到: “因内存压力而终止。进程以退出代码0结束”。这是为了模拟ios系统如何因内存压力而终止后台应用程序。

  4. 与另一部iphone No.2开始一个灯塔并开始播放。

  5. 结果:那些重新启动的回调永远不会被调用。

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

    谢谢!

3 个答案:

答案 0 :(得分:12)

当您单击主页按钮将应用程序发送到后台时,它会暂停,并且可以处理蓝牙代表并在后台运行10秒,此功能可以通过“在info.plist中的后台模式中添加蓝牙中心”来实现,并且不使用State Preservation&恢复。

如果您的应用由于内存压力而被IOS终止,它将无法再处理蓝牙代表。在这种情况下,如果您使用了State Preservation&恢复,您的应用程序可以重新启动到后台再次运行,也只有10秒。 10秒后,它将进入暂停状态。 只有在这种情况下,才能触发CBCentralManager的willRestoreState。

您可以添加代码

kill(getpid(),SIGKILL);

按钮操作,当您单击按钮时,您的应用程序将被IOS终止,就像被内存压力所杀,然后“willRestoreState”将被触发。

祝你好运。

答案 1 :(得分:3)

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

答案 2 :(得分:3)

对于已知服务UUIDs的外围设备的后台扫描,我也遇到此问题。也许这是iOS中的一个错误。我发现iOS在发现外围设备时会重新启动应用程序,可以通过观察XCode中设备管理器的控制台输出来看到。 didFinishLaunchingWithOptions委托被调用,但对CBCentralManager's willRestoreState委托的调用会延迟,直到用户手动将应用程序带到前台。

即使应用程序已启动,就好像主线程上的事件循环不会运行一样。例如,添加代码时:

dispatch_async(dispatch_get_main_queue(), ^{
  NSLog(@"Hello from the main thread");
});

didFinishLaunchingWithOptions委托,在应用程序移动到前台之前,消息不会显示在调试控制台中。

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