2

我正在尝试在applicationWillResignActive用户打开任务切换器期间运行一些代码,并且它运行良好,直到我开始在我的应用程序中使用蓝牙。

当蓝牙尝试连接到设备时,它会显示一个警告窗口,询问用户是否要配对设备。此警报足以触发该applicationWillResignActive方法,然后在应用程序被导航离开时运行我的代码(任务切换器)。这会导致一个大问题,因为我打算在切换时运行的代码会关闭实际应用程序中一些非常需要的功能。因此,一旦他们在该警报上按下“配对”或“取消”,我的所有应用程序都会停止正常运行,因为该应用程序失去了焦点。

我试图在这段时间内检测应用程序的状态......NSUInteger state = [[UIApplication sharedApplication] applicationState];当然,当警报弹出时它会被认为是活动的,而在任务切换器中它会被认为是非活动的。但是,情况并非如此,它在两个用例中都显示为活动状态。

更新#1

问题...

如何在应用程序中区分导致系统级非活动焦点状态的应用程序(如运行代码以连接到蓝牙)与用户导致系统级非活动焦点(如双击主页按钮)?一切都在努力区分导致该applicationWillResignActive方法触发的原因。

更新#2

NSUserDefaults此功能的目的是在蓝牙连接到设备时设置一个标志。该标志被“观察”并用于触发将视图控制器更改为与此新 BT 连接相关的页面。当用户双击主页按钮并移动到任务切换器时,我关闭 BT 并切换到 iBeacon,以便我可以通知事件。当前实现所有 bar 1 用例都很好。

如果用户尚未连接到 BT 设备并且它是第一次连接并且出现配对警报,它会触发该applicationWillResignActive方法,就像双击主页按钮一样。在此方法中,代码然后检查该NSUserDefaults标志以查看它是否打开(此时这是因为 BT 已经到达CBCentralManager'didConnectPeripheral方法并打开它),如果它打开,它会关闭 BT 并切换到扫描 iBeacon。因为该应用程序仍处于打开状态,这显然会导致问题。该应用程序正在运行,因此用户看到 BT 连接,新视图滑入,配对警报出现,然后新视图滑出,iBeacon 开始发送通知,供用户在任务切换器中使用。

我已经在applicationWillEnterBackground方法中发生了这个确切的功能,所以这不是答案。我需要有一种方式说“应用程序正在运行,我们收到了警报而不是双击主页,所以请不要关闭 BT 并打开 iBeacon”

4

1 回答 1

1

两种可能的解决方案:

1. 答案可能就在这句话中:

当蓝牙尝试连接到设备时,它会显示一个警告窗口,询问用户是否要配对设备。

您的应用必须执行某些操作才能显示此警报。您可以Date在发生这种情况时将一个字段设置为当前时间AppDelegate,然后当您接到电话时,applicationWillResignActive您可以将该时间戳与当前时间进行比较,如果它小于 1 秒左右,那么您有一个很好的线索蓝牙对话框出现了。

当然,这并非万无一失。正如@danh 在他的评论中指出的那样,iOS 的设计让这变得非常困难。您无法确定蓝牙对话框是否出现,或者用户或操作系统是否恰好同时将其他东西带到前台。更重要的是,即使出现蓝牙对话框,用户也可能在那一刻决定去查看他或她的电子邮件或开始浏览 Facebook。在这种情况下,蓝牙对话框确实是将您的应用程序发送到后台的原因,并且用户导航离开了应用程序。不幸的是,iOS 并没有真正为您提供区分两者的方法。

2. 您可以使用后台任务来处理您的清理逻辑。

您可以在调用 后请求最多 180 秒的后台运行时间applicationWillResignActive,因此您可以推迟清理任务,直到您的应用程序退出到后台后 175 秒。如果用户在 3 分钟内没有回来,则可能是时候进行此清理了。我的博文在这里展示了设置后台任务的基础知识。它专门用于延长信标测距时间,但您可以将所需的任何逻辑放入后台代码块中,如下所示:

- (void)extendBackgroundRunningTime {
  if (_backgroundTask != UIBackgroundTaskInvalid) {
    // if we are in here, that means the background task is already running.
    // don't restart it.
    return;
  }
  NSLog(@"Attempting to extend background running time");

  __block Boolean self_terminate = YES;

  _backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"DummyTask" expirationHandler:^{
    NSLog(@"Background task expired by iOS");
    if (self_terminate) {
        [[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
        _backgroundTask = UIBackgroundTaskInvalid;
    }
  }];



 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"Background task started.  Waiting 175 seconds before cleanup.");
    [NSThread sleepForTimeInterval:175];

    //TODO: perform cleanup code if app is not in the foreground by now

  });
}
于 2017-07-19T14:24:20.280 回答