Continuous location in background or after suspension

I am writing an iOS app that requires continuous location updates while being in the background. I am using CLLocationManager and here is what I am doing:


1) Requesting always authorization

2) Enabling background location in info.plist

3) Setting allowsBackgroundLocationUpdates to true

4) Starting location updates while in the foreground


The app gets location updates when in foreground. App also continues to get location updates in background every 1 second, until some time when the app gets suspended and does not get any further location updates. When the app gets suspended varies from anywhere between few 10s of minutes to hours. I have even noticed that the app sometimes does not get suspended but stops getting location updates.


My question is: is there a way to continuously get location updates indefinitely (or say for 24 hours) with the app in the background and not getting suspended. And if the app gets suspended, is there a way to wake up the app and resume getting continuous location updates without the user bringing the app to the foreground?


I have tried significantLocationUpdate to wake up the app and restart my location manager. With this I am able to get significantLocationUpdates for days but I get location updates about once every 5 minutes (while driving) but the location manager that I create and start to get continous frequent locations does not return any locations. I would like to get it more frequently, like once every few seconds.


Any help would be much appreciated.


Thanks.

Replies

You need to deal with two important facts:

1. Your app will get suspended and resumed.

2. Your app will get suspended, terminated, and relaunched by the system.

and iOS is going to do either or both of those things between location updates.


If you don't handle both of those cases correctly, then your app is going to stop receiving updates when you hit the case you're not dealing with right. The most likely case is that you're not handling the location key properly.

> I would like to get it more frequently, like once every few seconds.


Which is more important to your app? Update frequency or accuracy?


As you note, sLUs are the result of course grain changes. Does the app track and map a travelled route or does it provide turn-by-turn navigation, or...?


If nav, you should instead be using kCLLocationAccuracyBestForNavigation


It sounds to me tho, that your app is a tracker, in which case you need to focus on energy use first, I think, then take what the system provides in terms of accuracy


See:

- kCLLocationAccuracyBestForNavigation


- https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LocationBestPractices.html

Request Quick Location Updates

If your app just needs a quick fix on the user’s location, it’s best to call the

requestLocation
method of the location manager object, as shown in Listing 14-1. Doing so automatically stops location services once the request has been fulfilled, letting location hardware power down if not being used elsewhere. Location updates requested in this manner are delivered by a callback to the
locationManager:didUpdateLocations:
delegate method, which you must implement in your app.

Thanks for your response. Could you elaborate on how I need to handle these cases? How do I identify these two cases happening and what do I need to do in each of these cases? Also, I am not sure what you mean by location key. b.t.w, I am ssuming you are talknig about location updates and not significant location change?

Happy to report that I finally got it working. The app has been capturing my trips as expected in the background for 5 days straight now. The key was to detect driving and only then increase the frquency of location updates (to use GPS chip), along with setting locationManager.pausesLocationUpdatesAutomatically to false (as suggested by KMT -- thanks!!)


1) Start off with low accuracy location updates (KM accuracy, which uses only cell tower, no GPS chip)

2) When driving is detected (based on change in location), increase location accuracy to bestForNavigation

3) When driving seems to have ceased (based on speed or change in location), reduce location accuracy back to KM

4) At all times, keep locationManager.pausesLocationUpdatesAutomatically set to false


Hope this helps others too!

Hi karela,

It would be great if you shared some code for step 2 and step 3 that how you detect driving or ceased?

I have the same problem with you and I've just despaired than I saw your question and you solved that makes me happy?

I will try to achive this problem myself,


But as I said it would be greate if you share some parts.


Thanks.

Karela is this solution still working for you in the latest versions of iOS???

Hi Karela,
I also have very similar problem statement to get location updates after every few seconds irrespective of the activity of an individual, what I observed while testing my code is that the app is giving location updates in background mode for hours and sometimes 1-2 days but then stops. My use case is to get location updates until the user kills the app. Also, I have used standard location update as I need updates after every few seconds so can't wait for a significant update. In implementation thing, I have done quite similar things


[self.locationManager setAllowsBackgroundLocationUpdates:YES];

[self.locationManager disallowDeferredLocationUpdates];

[self.locationManager setPausesLocationUpdatesAutomatically:NO];


self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

self.locationManager.distanceFilter = 0;

[self.locationManager requestLocation];

Can you throw some light over this, also I think since Apple allows background modes to get location updates and if the phone has sufficient memory, then it shouldn't be terminating the app. What do you think that why your app worked by changing desired accuracy (depending on activity)

Any help would be highly appreciated.

Hi,
I'm having the same issue. But my case is location service is stopping after a few minutes.
Did you re-start your location service in time to time?
Did you test this on latest iOS version (12.1)?
It would be great if you share some parts.
Thanks,

Hi Karela,


Could you please share the code that you used to get location event in background. I am developing similar app where we need continuous location update even in background. We have used following methods to get the location.

1. Get the permission from user for always allow location.

2. Added permission in plist

3, Enabled location in background capability.

4. Added geofencing for monitoring.

5. [self.locationManager setPausesLocationUpdatesAutomatically:NO];


After all this above mentioned steps we are not able to get locations after some time. Any help will be appreciated. We dont want to use monitor significant changes as we want location update after every certain intervals with good accuracy.


Please let me know what can we to make our app work in background continuously.


P.S. :- Our app also requires the location update even if app is killed by user.


Thanks in advance. :-)

Hi Karela,
I do have the same problem. I have been trying from many days. Could you please share the code so that it will helpful to me.

Post not yet marked as solved Up vote reply of PK17 Down vote reply of PK17
Hello, anything update on this?
I figured out a simple solution for XCode 11.6, iOS 13

Just do:
Code Block language
locationManager.allowsBackgroundLocationUpdates = true

while setPausesLocationUpdatesAutomatically, doesn't exist in my code so I assume it is set to false which is probably the default value.

Vote up if you liked my solution :)
Pick your target, make sure the location updates is checked in the background modes.

First the location manager setup :
Code Block
   func setUp(){
    Logger.log(classC: className, method: "setup", status: "Ok")
    manager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    manager?.allowsBackgroundLocationUpdates = true
    manager?.activityType = .otherNavigation
    manager?.pausesLocationUpdatesAutomatically = false
    manager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
     
   
  }
   


Then use the geofencing to wake it up once and for all by updates it's monitoring. the '"regular one" and the geofencing one.

geofencing :
Code Block
func monitorRegionAtLocation(identifier: String ) {
     
     
    if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
      let maxDistance = 100.0
       
      guard let manager = manager else {return}
      guard let location = manager.location else {return}
       
      let coordinate2d = location.coordinate
      let region = CLCircularRegion(center: coordinate2d,
         radius: maxDistance, identifier: identifier)
      region.notifyOnEntry = true
      region.notifyOnExit = true
       
     
      manager.startMonitoring(for: region)
    }
  }



regular :

Code Block
     Logger.log(classC: className, method: "startMonitoring", status: "Ok")
    guard let manager = manager else {return}
     
 
      manager.startUpdatingLocation()
      manager.startMonitoringSignificantLocationChanges()
      monitorRegionAtLocation(identifier: "Home")
       
  }



geofencing callbacks :
Code Block
   func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    startMonitoring()
    lookUpCurrentLocation()
    checkLastDateSent(method: "didEnterRegion")
     
  }
   
  func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    startMonitoring()
    lookUpCurrentLocation()
    checkLastDateSent(method: "didExitRegion")
  }



Here the method lookUpCurrentLocation() is using the location manger to require something, forcing it to stay awak while the app is currently dead .

example or lookUpCurrentLocation :

Code Block
   func lookUpCurrentLocation(){
    Logger.log(classC: className, method: "lookUpCurrentLocation", status: "Ok")
    guard let manager = manager else {
      Logger.log(classC: className, method: "lookUpCurrentLocation", status: "location manager is null")
      return
       
    }
     
    let lastLocation = manager.location
    if let lastLocation = lastLocation {
      currentLoc["accuracy"] = lastLocation.horizontalAccuracy
         
      currentLoc["latitude"] = lastLocation.coordinate.latitude
      currentLoc["longitude"] = lastLocation.coordinate.longitude
      if let listener = listener {
        listener.currentLocation(location : currentLoc )
      }else{
        Logger.log(classC: className, method: "lookUpCurrentLocation", status: "location listener is null")
      }
    }else{
      Logger.log(classC: className, method: "lookUpCurrentLocation", status: "could not get last location")
    }
   
  
  }


Instead of loggers, you could schedule notifications to have a look at your location updates.
After your exit the geofencing zone for the first time the location arrow at the top of the screen will stay solid and you'' keep getting locations updates.

  • @Boulomiel - thanks for the detailed write-up. Can I connect with you to ask a few more questions on the background-based mileage tracking, having some trouble getting this to work.

  • Hello I tried your code for a while but couldn’t get it working.

    After your exit the geofencing zone for the first time the location arrow at the top of the screen will stay solid and you'' keep getting locations updates : My application is getting suspended after 10 seconds.

    can you tell me more how you can keep it ranning in the background.

    thanks

Add a Comment

@gpstracker did you find any solution for this?