当应用程序处于后台时,位置跟踪会在一段时间后停止

Location tracking stops after a while when app is in the background

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

我启用了以下背景模式,

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 文档中看到过时间限制。

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

您应该会看到 application(_:didFinishLaunchingWithOptions:) 被调用,并且 'location' 键应该出现在启动选项中。然后您可以重新创建正在使用这些位置的任何内容并继续录制。

如果不重新启动它可能会太耗内存。检查应用程序的内存消耗,看是否正在调用applicationDidReceiveMemoryWarning(_:)

搜索参考资料后(谈论任何限制),我认为 Apple Core Location Best Practices 视频 session 可能会有用!在 06:53 谈论后台的标准位置:

furthermore, Core Location won't take any action to ensure your app continues to run, so if you have background run for some reason and you decide to start a location session you might get some updates, but you might also get suspended before you receive all information that you hope to receive...

实际上,我以前遇到过这个问题,-作为解决方法-核心位置用于持续跟踪用户的位置,以执行与其位置无关的功能-上传文件-,但此解决方法没有'自 iOS 9 发布以来无法使用;我什至发了一个 question 提到这个问题。

但是,您的情况似乎与我遇到的情况不一样,如果您的目标是:

... creates local notification for every time location is updated.

那么您可能需要遵循与 User Notification Framework 集成的方法 - UNLocationNotificationTrigger:

The geographic location that the user must reach to enable the delivery of a local notification.

视频中也提到了session (08:59)。

可能这不是您想要的,但由于我们无法保证后台执行会继续 运行,您可能会以某种方式将其集成到您的应用程序中以实现所需的功能。

iOS11 的更新:

您可能需要检查 this answer 请求位置访问权限的正确方法。

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

locationManager.pausesLocationUpdatesAutomatically = false

我假设你还没有实现后台任务。你可以阅读 here.

在上面的 link 部分 “实施长-运行 任务” 点中。 3是你的情况,所以你可以在你的项目中使用后台位置更新是有效的,同样你也需要实施后台任务。

跟踪用户位置的方法有以下三种(根据上文 link 部分 “跟踪用户位置” ):-

  1. 仅限前台的定位服务(适用于您的情况)

  2. 显着变化的位置服务(推荐),但我认为它不能用于你的情况,因为你想每 10 米更新一次用户位置它适用于 ~500 米,更多信息请参阅 here

  3. 后台定位服务(我想你正在尝试这个)解决方案是添加后台任务。

    以下是后台任务示例,您可以根据需要进行修改,它在过去 2 小时内对我有效,我的应用程序仍在后台更新位置。

。 在您的 AppDelegate class 中,请更新以下功能,然后 运行 您的应用在后台运行。

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

下面是我的ViewControllerclass

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()
    }

}

降低准确性

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

self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

您可以使用 CLLocationAccuracy 常量之一

IMPORTANT

By default, standard location updates on iOS devices run with an accuracy level of best. Change these settings to match your app’s requirements. Otherwise, your app will unnecessarily waste energy.


自动暂停

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

self.locationManager.pausesLocationUpdatesAutomatically = true

IMPORTANT

For apps that have in-use authorization, a pause to location updates ends access to location changes until the app is launched again and able to restart those updates. If you do not wish location updates to stop entirely, consider disabling this property and changing location accuracy to kCLLocationAccuracyThreeKilometers when your app moves to the background. Doing so allows you to continue receiving location updates in a power-friendly manner.


允许后台更新

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

self.locationManager.allowsBackgroundLocationUpdates = true

Apps that want to receive location updates when suspended must include the UIBackgroundModes key (with the location value) in their app’s Info.plist file and set the value of this property to true. The presence of the UIBackgroundModes key with the location value is required for background updates


指定 Activity 类型

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

self.locationManager.activityType = .automotiveNavigation 

您可以使用 CLActivityType 案例之一


Defer Location Update

On supported devices with GPS hardware, you can let the location manager defer the delivery of location updates when your app is in the background. For example, a fitness app that tracks the user’s location on a hiking trail can defer updates until the user has moved a certain distance or a certain period of time has elapsed.


我 运行 进入其中 QT 应用程序将在一两个小时后停止在后台获取位置事件。

在 App Delegate 中,当应用程序进入后台时,我会停止 CLLocationManager,将精度从 kCLLocationAccuracyBest 降低到 kCLLocationAccuracyNearestTenMeters 并将距离过滤器从 None 增加到 50 米,然后它会跟踪超过 24 小时。