108

这是CLLocationManager文档中使用startMonitoringSignificantLocationChanges描述应用程序行为的部分:

如果您启动此服务并且您的应用程序随后终止,则系统会在新事件到达时自动将应用程序重新启动到后台。在这种情况下,传递给 application:didFinishLaunchingWithOptions: 应用程序委托方法的选项字典包含键 UIApplicationLaunchOptionsLocationKey 以指示您的应用程序是由于位置事件而启动的。重新启动后,您仍然必须配置位置管理器对象并调用此方法以继续接收位置事件。当您重新启动位置服务时,当前事件会立即传递给您的委托。此外,即使在您启动位置服务之前,您的位置管理器对象的位置属性也会填充最新的位置对象。

所以我的理解是,如果您的应用程序终止(并且我假设您不从applicationWillTerminate调用stopMonitoringSignificantLocationChanges ),您将被application:didFinishLaunchingWithOptions的UIApplicationLaunchOptionsLocationKey参数唤醒。此时,您创建CLLocationManager,调用startMonitoringSignificantLocationChanges并在有限的时间内进行后台位置处理。所以我对这一点很好。

上一段只讨论了应用程序终止时会发生什么,并没有建议您在应用程序暂停时做什么。didFinishLaunchingWithOptions的文档说:

该应用程序在后台跟踪位置更新,已被清除,现在已重新启动。在这种情况下,字典包含一个键,表明应用程序由于新的位置事件而重新启动。

建议您仅在您被终止后启动应用程序(由于位置更改)时才会收到此呼叫。

然而,位置感知编程指南中关于重大变化服务的段落有以下说法:

如果您保持此服务运行并且您的应用程序随后被暂停或终止,则该服务会在新的位置数据到达时自动唤醒您的应用程序。在唤醒时,您的应用程序将进入后台并给予少量时间来处理位置数据。因为您的应用程序在后台,所以它应该做最少的工作并避免任何可能阻止它在分配的时间到期之前返回的任务(例如查询网络)。如果没有,您的申请可能会被终止。

这表明如果您的应用程序已暂停,您会被位置数据唤醒,但没有提及您是如何被唤醒的:

在写这篇文章的过程中,我想我可能刚刚回答了我自己的问题,但如果我对这个问题的理解得到更有知识的人的证实,那就太好了。

4

4 回答 4

81

自从我提出这个问题以来,我已经进行了相当多的测试(主要是在上下班之间的火车上),并确认暂停应用的行为与我在问题末尾所怀疑的一样。

也就是说,您暂停的应用程序被唤醒,您不会在您的应用程序委托上收到任何回调,而是通过现有的CLLocationManagerDelegate接收您的位置更新。您可以通过检查applicationState来检测您正在后台运行,并针对您从挂起状态唤醒以进行定位处理的情况做有限的工作。

[UIApplication sharedApplication].applicationState == UIApplicationStateBackground

我通过一个位置测试工具得出了这个结论,欢迎您下载和试用。这是一个非常简单的应用程序,允许您通过 UI 打开重大更改和 GPS 更改 API,并记录您返回的所有响应。

注意上一个答案中的第六点不正确。冻干的暂停应用在从暂停状态唤醒时会收到CLLocationManagerDelegate回调。

于 2010-08-14T14:18:25.717 回答
25

我的理解如下(我正在写一个依赖这个API的应用程序,但还没有完成这个组件足以开始测试):

  1. 您的应用程序第一次运行,您注册startMonitoringSignificantLocationChanges并提供回调函数。当您的应用程序正在运行时,它会在收到重大更改时调用该回调。

  2. 如果您的应用程序被置于后台, UIApplication 将收到applicationWillResignActive,然后是applicationDidEnterBackground

  3. 如果您的应用程序在暂停时被杀死,您将不会收到通知;但是,如果您的应用程序在运行时被杀死(据我所知是前台或后台),您将获得一段时间的applicationWillTerminate。您不能从此函数请求额外的后台时间。

  4. 尽管在后台被杀死,操作系统将重新启动您的应用程序。如果您的应用程序只是由操作系统启动以进行更改,您将收到对应用程序 didFinishLaunchingWithOptions的调用:

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])
    

将帮助您确定您是否已从后台位置更改中恢复过来。5. 相反,如果您当前在后台运行,并且您的应用程序由用户手动重新启动,您将收到applicationWillEnterForeground后跟applicationDidBecomeActive。6.不管它是如何发生的,当你的应用程序重新启动时(除非它由于后台任务而仍在后台运行并且所述任务已开始监视更改),你需要明确告诉它startMonitoringSignificantLocationChanges再次因为“冷冻干燥”后不再附加回调。是的,一旦从挂起状态恢复后重新附加某种位置处理程序,您只需要在 didUpdateToLocation 中实现代码。

这就是我现在正在进行的代码开发。正如我之前提到的,我还没有准备好在设备上进行测试,所以我无法判断我是否正确解释了所有内容,所以评论者请随时纠正我(尽管我已经对话题)。

哦,如果运气不好,你发布了一个应用程序来做我想做的事,我可能会哭:)

祝你好运!

于 2010-08-10T04:54:28.640 回答
1

如果应用程序由于位置更改而从挂起状态唤醒,应用程序将以后台状态启动。

所有对象都将处于活动状态,您将在现有委托中收到位置更新。

于 2015-01-27T10:37:18.657 回答
0

所以我只有一个重要的说明,特定于应用程序何时终止:

对于可以在后台启动应用程序并稍后需要接收处理该启动的回调的某些 API,可能需要delegate设置一个对象。

因此,如果您因为位置跟踪而启动应用程序(即从终止状态,而不是暂停状态),那么您的 locationManager 委托回调将不会被调用,除非您在didFinishLaunching. 更准确地说,在设置委托之前,您不会收到任何委托回调。

  1. 因此,如果您在应用启动后在 ABC 视图控制器中进行跟踪
let manager = CLLocationManager()
manager.delegate = self
  1. 然后应用程序被终止
  2. 然后由于后台位置更改,应用程序是位置
  3. 在您将应用程序置于前台并打开您的 ABC 视图控制器之前,您不会收到回调

认为应用程序神奇地知道委托对象是什么是不正确的。它不会保留该信息。

解决方案:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
   let myLocationManager = CLLocationManager()
   myLocationManager.delegate = self
}

我想出了一个完全不相关的 API:

optional func userNotificationCenter(_ center: UNUserNotificationCenter, 
                      didReceive response: UNNotificationResponse, 
              withCompletionHandler completionHandler: @escaping () -> Void)

也就是说,如果您没有在 AppLaunch 之前设置代理,那么您会错过用户与应用程序终止后立即发生的通知的交互。更准确地说,在设置 userNotification 的委托之前,您会错过任何回调。

于 2021-03-11T10:10:52.697 回答