CoreBluetooth状态保存问题:iOS 7.1中未调用willRestoreState

CoreBluetooth状态保存问题:在iOS 7.1中不调用willRestoreState

大家好。 过去几周我一直在做一个蓝牙LE项目,并且遇到了障碍。 我一直无法在iOS 7 / 7.1中恢复状态。 我遵循(我认为)所有的步骤苹果奠定了,并得到了一些线索在其他堆栈溢出post。

  1. 我向plist添加了适当的蓝牙许可
  2. 当我创build我的中央pipe理器时,我给它一个还原标识符密钥。
  3. 我总是用相同的密钥实例化CM
  4. 我将willRestoreState函数添加到CM委托

我的testing案例:

  1. 连接到外设
  2. 确认连接
  3. 模拟内存逐出(kill(getpid(),SIGKILL);)
  4. 传输数据

结果iOS 7:

该应用程序将在AppDelegate didFinishLaunchingWithOptions函数中响应,但launchOptions [UIApplicationLaunchOptionsBluetoothCentralsKey]中的NSArray内容始终是一个空数组。

iOS 7.1上的结果:

进展! 我可以在100%的时间内在UIApplicationLaunchOptionsBluetoothCentralsKey数组中看到我的CentralManager键,但willRestoreState永远不会被调用。

码:

//All of this is in AppDelegate for testing @import CoreBluetooth; @interface AppDelegate () <CBCentralManagerDelegate, CBPeripheralDelegate> @property (readwrite, nonatomic, strong) CBCentralManager *centralManager; @end - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionRestoreIdentifierKey:@“myCentralManager”}]; //Used to debug CM restore only NSArray *centralManagerIdentifiers = launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey]; NSString *str = [NSString stringWithFormat: @"%@ %lu", @"Manager Restores: ", (unsigned long)centralManagerIdentifiers.count]; [self sendNotification:str]; for(int i = 0;i<centralManagerIdentifiers.count;i++) { [self sendNotification:(NSString *)[centralManagerIdentifiers objectAtIndex:i]]; } return YES; } - (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)state { activePeripheral = [state[CBCentralManagerRestoredStatePeripheralsKey] firstItem]; activePeripheral.delegate = self; NSString *str = [NSString stringWithFormat: @"%@ %lu", @"Device: ", activePeripheral.UUID]; [self sendNotification:str]; } //sendNotification is a func that creates a local notification for debugging when device connected to comp 

当我运行testing时,当应用程序不在内存中时,我的BLE设备与手机通信时,didFinishLaunchWithOptions被调用为100%,但willRestoreState永远不会被调用。

任何和所有的帮助将是伟大的! 谢谢!

好吧,所以我不得不删除我的两个答案已经这个问题。 但是我想我终于明白了。

这个评论是你的问题的关键。 本质上来说,这个centralManager:willRestoreState:只有在操作系统强制closures的情况下才会调用,而外围设备 这不包括扫描外围设备 在进一步的调查中,如果您正在扫描服务UUID,并且应用程序以相同的方式被终止,或者您已经完成连接,则实际上会调用您的代理)。

复制:我有一个外设使用CoreBluetooth设置在我的MacBook上。 我在外设上做广告,让我的iPhone发现它。 然后,让OSX外围设备应用程序继续运行,在Mac上终止BT连接,然后从iOS设备的中央启动连接。 这显然将持续运行,因为外设是不可访问的(显然,连接尝试可以永远持续,因为蓝牙LE没有连接超时)。 然后我添加一个button到我的gui,并把它连接到我的视图控制器中的一个函数:

 - (IBAction)crash:(id)sender { kill(getpid(), SIGKILL); } 

这将杀死应用程序,就好像它被操作系统杀死一样。 一旦你试图连接点击button,崩溃的应用程序(有时需要两个水龙头)。

在您的Mac上激活蓝牙将导致iOS重新启动您的应用程序,并调用正确的处理程序(包括centralManager:willRestoreState:

如果你想debugging处理程序(通过设置断点),在Xcode中,在Mac上打开BT之前,设置一个断点,然后select“Debug> Attach to Process …> By Process Identifier or Name …” 。

在出现的对话框中,input您的应用程序的名称(应与您的目标相同),然后单击“附加”。 接着Xcode会在状态窗口中等待启动。 等待几秒钟,然后在OSX上打开BT。 确保你的外围设备仍然是广告,然后iOS会把它拿起来,重新启动你的应用程序来处理连接。

有可能有其他方法来testing这个(使用特征通知可能?),但这个stream程是100%可重复的,所以可能会帮助你testing你的代码最容易。

有同样的问题。 从我能解决的问题出发,在实例化CBCentralManager时需要使用自定义调度队列,并且willRestoreState方法将被触发。 我认为这是由于asynchronous事件不被默认队列处理(当使用“nil”),当你的应用程序由后台恢复线程启动。

  ... dispatch_queue_t centralQueue = dispatch_queue_create("com.myco.cm", DISPATCH_QUEUE_SERIAL); cm = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:@{CBCentralManagerOptionRestoreIdentifierKey:@"cmRestoreID",CBCentralManagerOptionShowPowerAlertKey:@YES}]; ... 

您需要将CentralManager移到自己的队列中。

您还需要使用恢复标识符实例化外围设备。