应用程序在后台运行一段时间后,位置跟踪会停止

我创建了一个简单的应用程序,它可以跟踪用户位置,并在每次更新位置时创建本地通知。

我启用了下面的背景模式,

在此处输入图像描述

let locationManager = CLLocationManager() open override func viewDidLoad() { locationManager.delegate = self; locationManager.desiredAccuracy = kCLLocationAccuracyBest; locationManager.distanceFilter = 10 locationManager.allowsBackgroundLocationUpdates = true locationManager.startUpdatingLocation() } open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { let notification = UILocalNotification() notification.alertBody = "location updated" notification.fireDate = Date() UIApplication.shared.scheduleLocalNotification(notification) } 

我为NSLocationAlwaysUsageDescription设置字符串并请求许可。 第一次加载应用时始终使用的用户授予权限。


它在应用程序处于前台时运行良好,当它仍然在后台仍然工作时至少在5-40分钟的时间范围内,可以通过电池或其他打开的应用程序进行更改。

问题是为什么它停止工作,它不会继续工作?

我从未在Apple文档中看到时间限制。

当应用移动到后台时切换到重要的位置更新。 如果应用程序无限期地在后台保持活动状态,iOS将卸载该应用程序。

 locationManager.pausesLocationUpdatesAutomatically = false 

在搜索引用(谈论任何限制)后,我认为Apple Core Location Best Practicesvideo会话可能很有用! 在06:53谈论背景中的标准位置:

此外,Core Location不会采取任何措施来确保您的应用程序继续运行,因此如果您因某些原因而运行后台并且您决定启动一个位置会话,您可能会获得一些更新,但您可能会在收到之前被暂停您希望收到的所有信息……

实际上,我之前遇到过这个问题, – 作为一种解决方法 – 核心位置用于跟踪用户的位置,以便对其位置执行无关的function – 这是上传文件 – 但是这种解决方法在iOS 9后无效已被释放; 我甚至发了一个提到这个问题的问题。

但是,如果您的目标是,您的情况似乎与我所面临的情况不同:

…每次更新位置时都会创建本地通知。

那么您可能需要遵循与用户通知框架集成的方法 – UNLocationNotificationTrigger :

用户必须达到的地理位置才能启用本地通知。

它也在video会话( 08:59 )中提到。

也许,这可能不是你想要的,但由于我们无法保证后台执行将继续运行,你可能 – 在某种程度上 – 找到一种方法将它集成到你的应用程序中以实现所需的function。

iOS 11更新:

您可能需要检查此答案以获取请求位置访问的正确方法。

由于它的声音,应用程序因内存限制而被杀死。 但是,当新位置可用时,应该重新启动它,如下所述: https : //developer.apple.com/documentation/uikit/uiapplicationlaunchoptionskey/1623101-location

您应该看到正在调用application(_:didFinishLaunchingWithOptions:) ,并且启动选项中应该存在’location’键。 然后,您可以重新创建消耗位置的任何内容并继续录制。

如果没有重新启动,那可能会让人感到内存不足。 检查应用程序的内存消耗,看看是否正在调用applicationDidReceiveMemoryWarning(_:)

降低准确性

设置位置管理器对象的desiredAccuracy属性

 self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation 

您可以使用CLLocationAccuracy常量之一

重要

默认情况下,iOS设备上的标准位置更新以最佳准确度运行。 更改这些设置以符合您应用的要求。 否则,您的应用程序将不必要地浪费能源。


自动暂停

将位置管理器对象的pausesLocationUpdatesAutomatically属性设置为true

 self.locationManager.pausesLocationUpdatesAutomatically = true 

重要

对于具有使用中授权的应用,暂停到位置更新会终止对位置更改的访问,直到应用再次启动并能够重新启动这些更新。 如果您不希望位置更新完全停止,请考虑在应用移动到后台时禁用此属性并将位置精度更改为kCLLocationAccuracyThreeKilometers 。 这样做可以让您以function友好的方式继续接收位置更新。


允许后台更新

将location Manager对象的allowsBackgroundLocationUpdates属性设置为true

 self.locationManager.allowsBackgroundLocationUpdates = true 

想要在挂起时接收位置更新的应用必须在其应用的Info.plist文件中包含UIBackgroundModes键(具有位置值),并将此属性的值设置为true。 后台更新需要存在具有位置值的UIBackgroundModes键


指定活动类型

设置activityType属性,让Core Location知道您的应用在给定时间执行的位置活动类型

 self.locationManager.activityType = .automotiveNavigation 

您可以使用其中一个CLActivityType案例


推迟位置更新

在支持GPS设备的设备上,当您的应用在后台时,您可以让位置管理员推迟发布位置更新。 例如,跟踪用户在远足径上的位置的健身应用可以推迟更新,直到用户移动了特定距离或经过了特定时间段。


  • 适用于iOS应用的能效指南 – 位置最佳实践
  • GettingLocationWhenSuspended

我假设你没有实现后台任务。 你可以在这里阅读。

在上面的链接“实施长时间运行的任务”一节中没有。 3是你的情况,所以你可以在你的项目中使用后台位置更新是有效的,同样你也需要实现后台任务。

有三种方法可以跟踪用户位置(如上面链接“跟踪用户位置” ): –

  1. 仅限前台的位置服务(适用于您的情况)
  2. 重大改变位置服务( 推荐 ),但我认为它不适用于你的情况,因为你想每10米更新一次用户位置,它可以工作约500米,更多请看这里
  3. 后台位置服务(我认为你正在尝试这个),解决方案是添加后台任务。

下面是后台任务的示例,您可以根据自己的要求进行修改,自上次工作2小时起,它对我有用,我的应用程序仍在后台更新位置。

在您的AppDelegate类中,请更新以下function,然后在后台运行您的应用程序。

 func applicationDidEnterBackground(_ application: UIApplication) { application.beginBackgroundTask(withName: "") {} } 

以下是我的ViewController类

 import UIKit import CoreLocation class ViewController: UIViewController, CLLocationManagerDelegate { let locationManager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() locationManager.delegate = self; locationManager.requestAlwaysAuthorization() locationManager.desiredAccuracy = kCLLocationAccuracyBest; locationManager.allowsBackgroundLocationUpdates = true locationManager.distanceFilter = kCLDistanceFilterNone Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in self.locationManager.startUpdatingLocation() } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { print("didUpdateLocations \(Date())") self.locationManager.stopUpdatingLocation() } } 

您需要在AppDelegate类,启动方法,applicationDidEnterBackground和applicationDidBecomeActive方法中进行一些更改。

为位置管理器创建sharedInstance。

仅供参考,请访问http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended

它可能对你有帮助。也请查看评论。