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

时间:2022-07-10 01:26:43

I've created a simple app which tracks user location and creates local notification for every time location is updated.

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

I enabled the background modes below,

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

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

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

I set string for NSLocationAlwaysUsageDescription and ask for permission. User grant permission for always usage when the app loaded first time.

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


It's working well when app is in the foreground, when it goes background still working at least in 5-40 minutes time range which is changeable by battery or other opened apps.

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

The problem is why it stops working, doesn't it expected to be keep working?

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

I've never seen a time limit in Apple docs.

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

6 个解决方案

#1


10  

Switch to significant location updates when the app moves to background. iOS will unload the app if it keep alive in the background indefinitely.

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

locationManager.pausesLocationUpdatesAutomatically = false

#2


2  

After searching for references (talking about any limitation), I assume that Apple Core Location Best Practices video session could be useful! at 06:53 talking about standard location in the background:

在搜索引用(谈论任何限制)后,我认为Apple Core Location Best Practices视频会话可能很有用!在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...

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

Actually, I faced this issue before, -as a workaround- the core location was used to keep tracking the location of the user to do unrelated functionality to its location -which is uploading files-, but this workaround didn't work since iOS 9 has been released; I even posted a question referring to this issue.

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

However, it seems your case is not identical to what I faced, if you are aiming to:

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

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

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

then you might need to follow the approach of integrating with User Notification Framework - UNLocationNotificationTrigger:

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

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

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

It is also mentioned in the video session (08:59).

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

Probably, this is could be not what are you looking for, but since we have no guarantee that the background execution will continue running, you might -somehow- find a way to integrate it in your app to achieve the desired functionality.

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

Update for iOS 11:

iOS 11更新:

You might need to check this answer for the proper way to request the location access.

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

#3


1  

By the sound of it the app is being killed due to memory constraints. It should however be re-launched when a new location becomes available, as described here: https://developer.apple.com/documentation/uikit/uiapplicationlaunchoptionskey/1623101-location

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

You should see application(_:didFinishLaunchingWithOptions:) being called, and the 'location' key should be present in the launch options. You'll can then re-create whatever is consuming the locations and continue recording.

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

If it's not being re-launched it could be too memory hungry. Check the memory consumption of the app and see if applicationDidReceiveMemoryWarning(_:) is being called.

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

#4


1  

Reduce Accuracy

Set the desiredAccuracy property of the location manager object

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

self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

You can use one of the CLLocationAccuracy constants

您可以使用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.

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


Auto-Pause

Set the pausesLocationUpdatesAutomatically property of the location manager object to true

将位置管理器对象的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.

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


Allow background updates

Set the allowsBackgroundLocationUpdates property of the location manager object to true

将location Manager对象的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

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


Specify an Activity Type

Set the activityType property to let Core Location know what type of location activity your app is performing at a given time

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

self.locationManager.activityType = .automotiveNavigation 

You can use one of the CLActivityType cases

您可以使用其中一个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.

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


#5


0  

I assume you haven't implement background task. You can read here.

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

In the above link under section "Implementing Long-Running Tasks" point no. 3 is your situation, so it's valid you can use background location update in your project and for same you need to implement a background task too.

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

There are three way to track user location(as per above link under section "Tracking the User’s Location" ) :-

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

  1. Foreground-only location services (which works in your case)
  2. 仅限前台的位置服务(适用于您的情况)
  3. The significant-change location service (Recommended), but I think it is not usable in your case as you want to update user location per 10 meter and it works for ~500 meters, for more please see here
  4. 重大改变位置服务(推荐),但我认为它不适用于你的情况,因为你想每10米更新一次用户位置,它可以工作约500米,更多请看这里
  5. Background location services (I think you are trying for this) and solution is to add a background task.
  6. 后台位置服务(我认为你正在尝试这个),解决方案是添加后台任务。

Below is example of background task and you can modify as per your requirement, it works for me since last 2 hours and my app still update location in background.

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

.

In your AppDelegate class please update below function and then run your app in background.

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

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

And below is my ViewController class

以下是我的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()
    }

}

#6


-2  

You need to do some changes in AppDelegate class ,launch method, applicationDidEnterBackground and applicationDidBecomeActive methods.

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

Create a sharedInstance for location manager.

为位置管理器创建sharedInstance。

FYI please go through this http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended

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

it might help you.Check comments as well.

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

#1


10  

Switch to significant location updates when the app moves to background. iOS will unload the app if it keep alive in the background indefinitely.

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

locationManager.pausesLocationUpdatesAutomatically = false

#2


2  

After searching for references (talking about any limitation), I assume that Apple Core Location Best Practices video session could be useful! at 06:53 talking about standard location in the background:

在搜索引用(谈论任何限制)后,我认为Apple Core Location Best Practices视频会话可能很有用!在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...

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

Actually, I faced this issue before, -as a workaround- the core location was used to keep tracking the location of the user to do unrelated functionality to its location -which is uploading files-, but this workaround didn't work since iOS 9 has been released; I even posted a question referring to this issue.

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

However, it seems your case is not identical to what I faced, if you are aiming to:

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

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

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

then you might need to follow the approach of integrating with User Notification Framework - UNLocationNotificationTrigger:

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

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

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

It is also mentioned in the video session (08:59).

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

Probably, this is could be not what are you looking for, but since we have no guarantee that the background execution will continue running, you might -somehow- find a way to integrate it in your app to achieve the desired functionality.

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

Update for iOS 11:

iOS 11更新:

You might need to check this answer for the proper way to request the location access.

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

#3


1  

By the sound of it the app is being killed due to memory constraints. It should however be re-launched when a new location becomes available, as described here: https://developer.apple.com/documentation/uikit/uiapplicationlaunchoptionskey/1623101-location

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

You should see application(_:didFinishLaunchingWithOptions:) being called, and the 'location' key should be present in the launch options. You'll can then re-create whatever is consuming the locations and continue recording.

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

If it's not being re-launched it could be too memory hungry. Check the memory consumption of the app and see if applicationDidReceiveMemoryWarning(_:) is being called.

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

#4


1  

Reduce Accuracy

Set the desiredAccuracy property of the location manager object

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

self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

You can use one of the CLLocationAccuracy constants

您可以使用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.

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


Auto-Pause

Set the pausesLocationUpdatesAutomatically property of the location manager object to true

将位置管理器对象的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.

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


Allow background updates

Set the allowsBackgroundLocationUpdates property of the location manager object to true

将location Manager对象的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

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


Specify an Activity Type

Set the activityType property to let Core Location know what type of location activity your app is performing at a given time

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

self.locationManager.activityType = .automotiveNavigation 

You can use one of the CLActivityType cases

您可以使用其中一个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.

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


#5


0  

I assume you haven't implement background task. You can read here.

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

In the above link under section "Implementing Long-Running Tasks" point no. 3 is your situation, so it's valid you can use background location update in your project and for same you need to implement a background task too.

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

There are three way to track user location(as per above link under section "Tracking the User’s Location" ) :-

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

  1. Foreground-only location services (which works in your case)
  2. 仅限前台的位置服务(适用于您的情况)
  3. The significant-change location service (Recommended), but I think it is not usable in your case as you want to update user location per 10 meter and it works for ~500 meters, for more please see here
  4. 重大改变位置服务(推荐),但我认为它不适用于你的情况,因为你想每10米更新一次用户位置,它可以工作约500米,更多请看这里
  5. Background location services (I think you are trying for this) and solution is to add a background task.
  6. 后台位置服务(我认为你正在尝试这个),解决方案是添加后台任务。

Below is example of background task and you can modify as per your requirement, it works for me since last 2 hours and my app still update location in background.

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

.

In your AppDelegate class please update below function and then run your app in background.

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

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

And below is my ViewController class

以下是我的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()
    }

}

#6


-2  

You need to do some changes in AppDelegate class ,launch method, applicationDidEnterBackground and applicationDidBecomeActive methods.

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

Create a sharedInstance for location manager.

为位置管理器创建sharedInstance。

FYI please go through this http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended

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

it might help you.Check comments as well.

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