Location Update Even When App Is Killed/Terminated

iOS swift backgound location update when killed/suspended with minimum data loss

question-1

What is the difference between using startMonitoringSignificantLocationChanges Vs startUpdatingLocation?

startUpdatingLocation updates the location when it is called first time and then when the distance filter value exceeds.

it uses the GPS when its available, if you use in continuously it Drain your power/battery

Discussion

This method returns immediately. Calling this method causes the
location manager to obtain an initial location fix (which may take
several seconds) and notify your delegate by calling its
locationManager:didUpdateLocations: method. After that, the receiver generates update events primarily when the value in the distanceFilter property is exceeded. Updates may be delivered in other situations though. For example, the receiver may send another notification if the hardware gathers a more accurate location reading.

Calling this method several times in succession does not automatically
result in new events being generated. Calling stopUpdatingLocation in
between, however, does cause a new initial event to be sent the next
time you call this method.

If you start this service and your application is suspended, the
system stops the delivery of events until your application starts
running again (either in the foreground or background). If your
application is terminated, the delivery of new location events stops
altogether. Therefore, if your application needs to receive location
events while in the background, it must include the UIBackgroundModes
key (with the location value) in its Info.plist file.

In addition to your delegate object implementing the
locationManager:didUpdateLocations: method, it should also implement
the locationManager:didFailWithError: method to respond to potential
errors.

startMonitoringSignificantLocationChanges when a significant change in position occurs.

it uses cellular or wifi, when it work the location is changed or its called in the particular Time interval.

Discussion

This method initiates the delivery of location events asynchronously,
returning shortly after you call it. Location events are delivered to
your delegate’s locationManager:didUpdateLocations: method. The first
event to be delivered is usually the most recently cached location
event (if any) but may be a newer event in some circumstances.

Obtaining a current location fix may take several additional seconds,
so be sure to check the timestamps on the location events in your
delegate method.

After returning a current location fix, the receiver generates update
events only when a significant change in the user’s location is
detected. For example, it might generate a new event when the device
becomes associated with a different cell tower. It does not rely on
the value in the distanceFilter property to generate events. Calling
this method several times in succession does not automatically result
in new events being generated. Calling stopMonitoringSignificantLocationChanges in between, however, does
cause a new initial event to be sent the next time you call this
method.

If you start this service and your application is subsequently
terminated, the system automatically relaunches the application into
the background if a new event arrives. In such a case, the options
dictionary passed to the locationManager:didUpdateLocations: method of
your application delegate contains the key
UIApplicationLaunchOptionsLocationKey to indicate that your
application was launched because of a location event. Upon relaunch,
you must still configure a location manager object and call this
method to continue receiving location events. When you restart
location services, the current event is delivered to your delegate
immediately. In addition, the location property of your location
manager object is populated with the most recent location object even
before you start location services.

Note:

Apps can expect a notification as soon as the device moves 500
meters or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.

for differenciate purpose I taken from here

question-2

If we use startUpdatingLocation does it impact on publishing the app to the App Store?

One of the possible reasons for 2.16 rejection is the absence of GPS battery warning in your app description on the app meta in iTunesConnect - "The continued use of GPS may decrease battery life" or something like that.

for More information related to this

Question-3

When the app is killed/suspended (Force closed by the user) it takes some time to restart the location manager from the AppDelegate which causes loss of location data for a period of time. Any possible solution to overcome this

NO, we Can't Over Come, reason the memory newly Initiated.

IOS Getting location updates when app terminated without using significantChange

Looking at the below content from the Apple doc, you clearly have 2 alternatives against using significant location changes to wake a app from the background. I have marked in bold the services you can use to relaunch the app if it has been terminated.

Using Location Services in the Background Most location services are
meant to be used while your app is in the foreground but some can also
run in the background. In some cases, location events can even cause
your app to be relaunched to process an event. To run most location
services in the background, you need to enable the location updates
background mode in the Capabilities tab of your Xcode project. For
services that launch your app, you need to request (and be granted)
“Always” authorization from the user.

The standard location service delivers events normally while an app is
running in the foreground. When your app is in the background, this
service delivers events only when the location-updates background mode
is enabled for the app. This service does not relaunch iOS apps that
have been terminated.

The significant location change service delivers events normally
while an app is running in the foreground or background. For a
terminated iOS app, this service relaunches the app to deliver
events.
Use of this service requires “Always” authorization from the
user.

The region monitoring service delivers events normally while an
app is running in the foreground or background. (You can use this
service for both geographic and beacon regions.) For a terminated
iOS app, this service relaunches the app to deliver events.
Use of
this service requires “Always” authorization from the user.

Beacon ranging delivers events normally while an app is running in the
foreground. When your app is in the background, this service delivers
events only when the location-updates background mode is enabled for
the app and the standard location service is running. (If the beacon
region’s notifyEntryStateOnDisplay property is YES, waking the device
causes the app to range for beacons for a few seconds in the
background.) This service does not relaunch iOS apps that have been
terminated; however, you can be relaunched by monitoring beacon
regions using the region monitoring service.

The heading service delivers events normally while an iOS app is
running in the foreground. When your app is in the background, this
service delivers events only when the location-updates background mode
is enabled for the app and the standard location service is running.
This service does not relaunch iOS apps that have been terminated.

The visit service delivers events normally while an iOS app is
running in the foreground. When your app is in the background, this
service delivers events only when the location-updates background mode
is enabled for the app and the standard location service is running.
For a terminated iOS app, this service relaunches the app to deliver events. Use of this service requires “Always” authorization from the
user.

Enabling the location-updates background mode ensures that an app
continues to receive location events while in the background. When the
app moves to the background, the system adds the location-services
indicator to the status bar to let the user know that an app is using
location services. The system may still terminate the app at any time
to reclaim its memory or other resources.

Also from the doc,

Getting the Visited Locations
In iOS, the visits service provides an alternative to the significant location change service for apps that need location
information about interesting places that the user visited.
For
example, if the user is in one location for an extended period of
time, the service might generate an event when the user arrives at
that location and another when the user leaves that location. The
service is intended for apps that might already be using the
significant location change service and want an even lower power way
to do so. You would not use this service to create navigation apps or
apps that rely on regular location updates.

Document Link:

https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/doc/uid/TP40007125-CH3-SW73

How to restart the location update when the app is killed by user?

I just solved this by using allowDeferredLocationUpdates

func applicationWillTerminate(_ application: UIApplication) {
Log.debug("Will Terminate")

self.locationManager?.stopMonitoringSignificantLocationChanges()
self.locationManager?.allowDeferredLocationUpdates(untilTraveled: 5, timeout: 60000)
self.locationManager?.startMonitoringSignificantLocationChanges()

}

How Can I Continue updating my location even when app is killed or removed from background in ios?

Its possible, but you'll have to jump through a few hoops.
The only way to send location updates when killed is by using Region Monitoring (https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/RegionMonitoring/RegionMonitoring.html).
When setup up, your app would be opened by the OS then you have a few seconds to process information before the app is killed. Its enough time to send location updates to your server/local storage.
There is also another API called CLVisit, however, its completely controlled by the operating system and not reliable.

iOS 13 track user location when app is killed

You have 2 options to track user location when app is killed:

1 -> Region Monitoring aka geofencing: You will setup a region to be monitored & when user enter or leave that region, the iOS system will wake up your app & notify you in application delegate about location update.
https://developer.apple.com/documentation/corelocation/monitoring_the_user_s_proximity_to_geographic_regions

2-> Significant-Change location service: In this case, iOS system will wake up your app only when user's location is significantly changed. The value is around 500 meters.
https://developer.apple.com/documentation/corelocation/getting_the_user_s_location/using_the_significant-change_location_service

Note: For both of these features to work, you will need 'Always' location permission from user.

Decided which method is suitable for you & then dive into the its documentation.

Receiving Location even when app is not running in Swift

It may or may not be a good solution but if I were you I would have used both startMonitoringSignificantLocationChanges and regionMonitoring.

Here is the sample I made which worked well with iOS 13.

Lets take regionMonitoring first. We have certainly no problems when the app is in foreground state and we can use the CLLocationManager's didUpdate delegate to get the location and send it to the server.

Keep latest current location in AppDelegate's property, lets say:

var lastLocation:CLLocation?

//And a location manager
var locationManager = CLLocationManager()

We have two UIApplicationDelegates

func applicationDidEnterBackground(_ application: UIApplication) {
//Create a region
}

func applicationWillTerminate(_ application: UIApplication) {
//Create a region
}

So whenever the user kills the app or makes the app go to background, we can certainly create a region around the latest current location fetched. Here is an example to create a region.

func createRegion(location:CLLocation?) {

if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
let coordinate = CLLocationCoordinate2DMake((location?.coordinate.latitude)!, (location?.coordinate.longitude)!)
let regionRadius = 50.0

let region = CLCircularRegion(center: CLLocationCoordinate2D(
latitude: coordinate.latitude,
longitude: coordinate.longitude),
radius: regionRadius,
identifier: "aabb")

region.notifyOnExit = true
region.notifyOnEntry = true

//Send your fetched location to server

//Stop your location manager for updating location and start regionMonitoring
self.locationManager?.stopUpdatingLocation()
self.locationManager?.startMonitoring(for: region)
}
else {
print("System can't track regions")
}
}

Make use of RegionDelegates

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Entered Region")
}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("Exited Region")

locationManager?.stopMonitoring(for: region)

//Start location manager and fetch current location
locationManager?.startUpdatingLocation()
}

Grab the location from didUpdate method

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

if UIApplication.shared.applicationState == .active {
} else {
//App is in BG/ Killed or suspended state
//send location to server
// create a New Region with current fetched location
let location = locations.last
lastLocation = location

//Make region and again the same cycle continues.
self.createRegion(location: lastLocation)
}
}

Here I have made a 50m region radius circle. I have tested this and it is called generally after crossing 100m from your center point.

Now the second approach can me using significantLocationChanges

On making the app go background or terminated, we can just stop location manager for further updating locations and can call the startMonitoringSignificantLocationChanges

self.locationManager?.stopUpdatingLocation()
self.locationManager?.startMonitoringSignificantLocationChanges()

When the app is killed, the location is grabbed from didFinishLaunching method's launchOptions?[UIApplicationLaunchOptionsKey.location]

if launchOptions?[UIApplicationLaunchOptionsKey.location] != nil {
//You have a location when app is in killed/ not running state
}

Make sure to keep BackgroundModes On for Location Updates
Sample Image

Also make sure to ask for locationManager?.requestAlwaysAuthorization() by using the key

<key>NSLocationAlwaysUsageDescription</key>
<string>Allow location</string>

in your Info.plist

There can be a third solution by taking 2 LocationManagers simultaneously.

  1. For region
  2. Significant Location Changes

As using significantLocationChanges

Apps can expect a notification as soon as the device moves 500 meters
or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.

as per the give Apple Doc

So it totally depends on your requirements as the location fetching depends on many factors like the number of apps opened, battery power, signal strength etc when the app is not running.

Also keep in mind to always setup a region with good accuracy.

I know that this will not solve your problem completely but you will get an idea to move forward as per your requirements.

Get Location Updates for iOS App Even when Suspended

After months of trials and errors by experimenting the Core Location Framework, I have found the solution to get location update even when the app is killed/suspended. It works well for both iOS 7 and 8.

Here is the solution:-

If your app is a location based mobile application that needs to monitor the location of the device when it has significant changes, the iOS will return you some location coordinates when the device has moved more than 500 meters from the last known location. Yes, even when the app is killed/suspended either by the user or iOS itself, you still can get the location updates.

So in order for a locationManager to get location update even when the app is killed/suspended, you must use the method startMonitoringSignificantLocationChanges, you can not use startUpdatingLocation.

When iOS wants to return the location update to the app, it will help you to relaunch the app and return a key UIApplicationLaunchOptionsLocationKey to the app delegate method didFinishLaunchingWithOptions.

The key UIApplicationLaunchOptionsLocationKey is very important and you must know how to handle it. You must create a new locationManager instance when you receive the key and you will get the location update on the locationManager delegate method didUpdateLocations.

Here is the sample code:-

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.shareModel = [LocationShareModel sharedModel];

if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
self.shareModel.anotherLocationManager = [[CLLocationManager alloc]init];
self.shareModel.anotherLocationManager.delegate = self;
self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;

if(IS_OS_8_OR_LATER) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}

[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];

}
return YES;
}

In addition to the didFinishLaunchingWithOptions method, I have created the locationManager instance when the app is active. Here are some code examples:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];

if(IS_OS_8_OR_LATER) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}

[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(self.shareModel.anotherLocationManager)
[self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];

self.shareModel.anotherLocationManager = [[CLLocationManager alloc]init];
self.shareModel.anotherLocationManager.delegate = self;
self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;

if(IS_OS_8_OR_LATER) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}

[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}

I have written an article explaining on the details on how to get the location update for iOS 7 and 8 even when the app is killed/suspended. I have also uploaded the complete source code on GitHub with the steps on how to test this solution.

Please visit the following URLs for more information:-

  1. Getting Location Updates for iOS 7 and 8 when the App is Killed/Terminated/Suspended
  2. Source Code on GitHub - Get the Location Updates Even when the iOS mobile apps is Suspended/Terminated/Killed


Related Topics



Leave a reply



Submit