CoreBluetooth 状态保存问题:在 iOS 7.1 中未调用 willRestoreState [英] CoreBluetooth state preservation issue: willRestoreState not called in iOS 7.1

查看:17
本文介绍了CoreBluetooth 状态保存问题:在 iOS 7.1 中未调用 willRestoreState的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

CoreBluetooth state preservation issue: willRestoreState not called in iOS 7.1

大家好.过去几周我一直在研究蓝牙 LE 项目,但遇到了障碍.我一直无法在 iOS 7/7.1 中使状态恢复正常工作.我已经遵循(我认为)Apple 列出的所有步骤,并在其他堆栈溢出帖子中获得了一些线索.

Hey all. I’ve been working on a Bluetooth LE project for the past few weeks, and hit a roadblock. I have been unable to get state restoration working properly in iOS 7 / 7.1. I’ve followed (I think) all of the steps Apple lays out, and got some clues on other stack overflow posts.

  1. 我向 plist 添加了适当的蓝牙权限
  2. 当我创建我的中央管理器时,我会给它一个恢复标识符密钥.
  3. 我总是使用相同的密钥实例化 CM
  4. 我在 CM 委托中添加了 willRestoreState 函数

我的测试用例:

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

结果 iOS 7:

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

The app would respond in the AppDelegate didFinishLaunchingWithOptions function, but the contents of the NSArray inside of launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey] was always an empty array.

iOS 7.1 上的结果:

Results on iOS 7.1:

进步!我可以 100% 地在 UIApplicationLaunchOptionsBluetoothCentralsKey 数组中看到我的 CentralManager 键,但永远不会调用 willRestoreState.

Progress! I can see my CentralManager key in the UIApplicationLaunchOptionsBluetoothCentralsKey array 100% of the time, but willRestoreState is never called.

代码:

//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

当我运行测试时,当应用不在内存中时,当我的 BLE 设备与手机通信时,didFinishLaunchWithOptions 被调用 100%,但 willRestoreState 从未被调用.

When I run the tests, didFinishLaunchWithOptions is called 100% when my BLE device communicates to the phone when the app is not in memory, but willRestoreState is never called.

任何帮助都会很棒!谢谢!

Any and all help would be great! thanks!

推荐答案

好的,所以我不得不删除我对这个问题的两个答案.但我想我终于想通了.

Okay, so I've had to delete two of my answers already to this question. But I think I've finally figured it out.

此评论是解决您问题的关键.本质上,这个 centralManager:willRestoreState: 仅在外围设备正在进行未完成的操作时被操作系统强制关闭时才会被调用(这不包括扫描外围设备 On进一步调查,如果您正在扫描服务 UUID 并且应用程序以同样的方式被杀死,或者您已经完成连接,它实际上会调用您的委托).

This comment is the key to your problem. Essentially, this centralManager:willRestoreState: only gets called if it's force closed by the OS while an outstanding operation is in progress with a peripheral (this does not include scanning for peripherals On further investigation, if you're scanning for a service UUID and the app is killed in the same way, or you've already finished connecting, it will in fact call your delegate).

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

To replicate: I have a peripheral using CoreBluetooth set up on my MacBook. I advertise on the peripheral, and have the central on my iPhone discover it. Then, leaving the OSX peripheral app running, kill your BT connection on your Mac and then initiate a connect from the central on your iOS device. This obviously will continuously run as the peripheral is non-reachable (apparently, the connection attempt can last forever as Bluetooth LE has no timeout on connections). I then added a button to my gui and hooked it up to a function in my view controller:

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

这将杀死应用程序,就像它被操作系统杀死一样.一旦您尝试连接,请轻按按钮使应用程序崩溃(有时需要轻按两次).

This will kill the app as if it was killed by the OS. Once you are attempting to connect tap the button to crash the app (sometimes it takes two taps).

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

Activating Bluetooth on your Mac will then result in iOS relaunching your app and calling the correct handlers (including centralManager:willRestoreState:).

如果您想调试处理程序(通过设置断点),请在 Xcode 中,在 Mac 上打开 BT 之前,设置一个断点,然后选择调试">附加到进程...">按进程标识符或名称"...'.

If you want to debug the handlers (by setting a breakpoint), in Xcode, before turning BT on on your Mac, set a breakpoint and then select 'Debug > Attach to Process... > By Process Identifier or Name...'.

在出现的对话框中,输入您的应用程序名称(应与您的目标相同),然后单击附加".Xcode 然后会在状态窗口中说等待启动.等待几秒钟,然后在 OSX 上打开 BT.确保您的外围设备仍在投放广告,然后 iOS 会接收它并重新启动您的应用以处理连接.

In the dialog that appears, type the name of your app (should be identical to your target) and click "Attach". Xcode will then say waiting for launch in the status window. Wait a couple seconds and then turn on BT on OSX. Make sure your peripheral is still advertising and then iOS will pick it up and relaunch your app to handle the connection.

可能还有其他方法来测试这个(可能对特征使用通知?)但这个流程是 100% 可重现的,因此可能会帮助您最轻松地测试您的代码.

There are likely other ways to test this (using notify on a characteristic maybe?) but this flow is 100% reproducible so will likely help you test you code most easily.

这篇关于CoreBluetooth 状态保存问题:在 iOS 7.1 中未调用 willRestoreState的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆