I'm looking for a way to get a background location update every n minutes in my iOS application. I'm using iOS 4.3 and the solution should work for non-jailbroken iPhones.
I tried / considered following options:
CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges
: This works in the background as expected, based on the configured properties, but it seems not possible to force it to update the location every n minutesNSTimer
: Does work when the app is running in the foreground but doesn't seem to be designed for background tasks- Local notifications: Local notifications can be scheduled every n minutes, but it's not possible to execute some code to get the current location (without the user having to launch the app via the notification). This approach also doesn't seem to be a clean approach as this is not what notifications should be used for.
UIApplication:beginBackgroundTaskWithExpirationHandler
: As far as I understand, this should be used to finish some work in the background (also limited in time) when an app is moved to the background rather than implementing "long-running" background processes.
How can I implement these regular background location updates?
Unfortunately, all of your assumptions seem correct, and I don't think there's a way to do this. In order to save battery life, the iPhone's location services are based on movement. If the phone sits in one spot, it's invisible to location services.
The
CLLocationManager
will only calllocationManager:didUpdateToLocation:fromLocation:
when the phone receives a location update, which only happens if one of the three location services (cell tower, gps, wifi) perceives a change.A few other things that might help inform further solutions:
Starting & Stopping the services causes the
didUpdateToLocation
delegate method to be called, but thenewLocation
might have an old timestamp.Region Monitoring might help
When running in the background, be aware that it may be difficult to get "full" LocationServices support approved by Apple. From what I've seen, they've specifically designed
startMonitoringSignificantLocationChanges
as a low power alternative for apps that need background location support, and strongly encourage developers to use this unless the app absolutely needs it.Good Luck!
UPDATE: These thoughts may be out of date by now. Looks as though people are having success with @wjans answer, above.
Here is what I use:
I start the tracking in AppDelegate like that:
I used xs2bush's method of getting an interval (using
timeIntervalSinceDate
) and expanded on it a little bit. I wanted to make sure that I was getting the required accuracy that I needed and also that I was not running down the battery by keeping the gps radio on more than necessary.I keep location running continuously with the following settings:
this is a relatively low drain on the battery. When I'm ready to get my next periodic location reading, I first check to see if the location is within my desired accuracy, if it is, I then use the location. If it's not, then I increase the accuracy with this:
get my location and then once I have the location I turn the accuracy back down again to minimize the drain on the battery. I have written a full working sample of this and also I have written the source for the server side code to collect the location data, store it to a database and allow users to view gps data in real time or retrieve and view previously stored routes. I have clients for iOS, android, windows phone and java me. All clients are natively written and they all work properly in the background. The project is MIT licensed.
The iOS project is targeted for iOS 6 using a base SDK of iOS 7. You can get the code here.
Please file an issue on github if you see any problems with it. Thanks.
I did this in an application I'm developing. The timers don't work when the app is in the background but the app is constantly receiving the location updates. I read somewhere in the documentation (i can't seem to find it now, i'll post an update when i do) that a method can be called only on an active run loop when the app is in the background. The app delegate has an active run loop even in the bg so you dont need to create your own to make this work. [Im not sure if this is the correct explanation but thats how I understood from what i read]
First of all, add the
location
object for the keyUIBackgroundModes
in your app's info.plist. Now, what you need to do is start the location updates anywhere in your app:Next, write a method to handle the location updates, say
-(void)didUpdateToLocation:(CLLocation*)location
, in the app delegate. Then implement the methodlocationManager:didUpdateLocation:fromLocation
ofCLLocationManagerDelegate
in the class in which you started the location manager (since we set the location manager delegate to 'self'). Inside this method you need to check if the time interval after which you have to handle the location updates has elapsed. You can do this by saving the current time every time. If that time has elapsed, call the method UpdateLocation from your app delegate:This will call your method every 5 mins even when your app is in background. Imp: This implementation drains the battery, if your location data's accuracy is not critical you should use
[locationManager startMonitoringSignificantLocationChanges]
Before adding this to your app, please read the Location Awareness Programming Guide
There is a cocoapod APScheduledLocationManager that allows to get background location updates every n seconds with desired location accuracy.
The repository also contains an example app written in Swift 3.
I found a solution to implement this with the help of the Apple Developer Forums:
location background mode
NSTimer
in the background withUIApplication:beginBackgroundTaskWithExpirationHandler:
n
is smaller thanUIApplication:backgroundTimeRemaining
it will work just fine. Whenn
is larger, thelocation manager
should be enabled (and disabled) again before there is no time remaining to avoid the background task being killed.This works because location is one of the three allowed types of background execution.
Note: I lost some time by testing this in the simulator where it doesn't work. However, it works fine on my phone.