By wjans

2011-06-14 17:23:18 8 Comments

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 minutes
  • NSTimer: 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?


@Malcolm 2018-01-17 17:31:36

In iOS 9 and watchOS 2.0 there's a new method on CLLocationManager that lets you request the current location: CLLocationManager:requestLocation(). This completes immediately and then returns the location to the CLLocationManager delegate.

You can use an NSTimer to request a location every minute with this method now and don't have to work with startUpdatingLocation and stopUpdatingLocation methods.

However if you want to capture locations based on a change of X meters from the last location, just set the distanceFilter property of CLLocationManger and to X call startUpdatingLocation().

@Hari R Krishna 2017-09-06 07:42:25

Working Code(Entire Stepwise Code)

Step 1

  • Go to project -> Capabilities -> Background Modes -> select Location updates.
  • Go to Project -> Info -> add a key NSLocationAlwaysUsageDescription with an optional string.

Step 2

Add this code to AppDelegate.m

@interface AppDelegate ()<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSTimer *timer;

Step 3 Add This Code in to applicationDidEnterBackground method in AppDelegate.m

    - (void)applicationDidEnterBackground:(UIApplication *)application {
        UIApplication *app = [UIApplication sharedApplication];
        __block UIBackgroundTaskIdentifier bgTaskId =
        [app beginBackgroundTaskWithExpirationHandler:^{
            [app endBackgroundTask:bgTaskId];
            bgTaskId = UIBackgroundTaskInvalid;

        dispatch_async( dispatch_get_main_queue(), ^{
            self.timer = nil;
            [self initTimer];
            [app endBackgroundTask:bgTaskId];
            bgTaskId = UIBackgroundTaskInvalid;

- (void)initTimer {
    if (nil == self.locationManager)
        self.locationManager = [[CLLocationManager alloc] init];

    self.locationManager.delegate = self;
    [self.locationManager requestAlwaysAuthorization];
    [self.locationManager startMonitoringSignificantLocationChanges];
    if (self.timer == nil) {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3

- (void)checkUpdates:(NSTimer *)timer{
    UIApplication *app = [UIApplication sharedApplication];
    double remaining = app.backgroundTimeRemaining;
    if(remaining < 580.0) {
        [self.locationManager startUpdatingLocation];
        [self.locationManager stopUpdatingLocation];
        [self.locationManager startMonitoringSignificantLocationChanges];

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation {
    NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
    [self updateLocationWithLatitude:[newLocation coordinate].latitude andLongitude:[newLocation coordinate].longitude];
    UIApplication*    app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask =
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self initTimer];

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    [self.locationManager stopUpdatingLocation];
    UIApplication *app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask =
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    [self initTimer];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Do the work associated with the task

//Here you can update your web service or back end with new latitude and longitude

@vky 2017-12-20 07:00:43

Dear Hari, This code is working but location stop after 3 to 4 minutes.Do you tell me please where did i wrong i follow same code that u provided us.Thanks !

@Hari R Krishna 2017-12-21 12:56:46

Can you please try this code when initialising location manager.... self.locationManager.pausesLocationUpdatesAutomatically = NO; and please get back if issue remains :)

@Dhaval Bhadania 2018-08-09 05:05:24

@HariRKrishna is it working while the application on kill or terminate or suspend state also?

@Premal Khetani 2018-08-09 05:30:35

@HariRKrishna will it work more than 5 mins in ios 11 or more?

@Premal Khetani 2018-08-09 05:31:08

@DhavalBhadania if you found any solution for this issue please let me know.

@Premal Khetani 2018-08-10 06:41:07

@HariRKrishna this code works only till 10 mins max when the app is in the background. Can you please tell me if we need more time to do work, what we should do?

@Leszek Szary 2015-02-06 19:24:42

On iOS 8/9/10 to make background location update every 5 minutes do the following:

  1. Go to Project -> Capabilities -> Background Modes -> select Location updates

  2. Go to Project -> Info -> add a key NSLocationAlwaysUsageDescription with empty value (or optionally any text)

  3. To make location working when your app is in the background and send coordinates to web service or do anything with them every 5 minutes implement it like in the code below.

I'm not using any background tasks or timers. I've tested this code with my device with iOS 8.1 which was lying on my desk for few hours with my app running in the background. Device was locked and the code was running properly all the time.

@interface LocationManager () <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSDate *lastTimestamp;


@implementation LocationManager

+ (instancetype)sharedInstance
    static id sharedInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
        LocationManager *instance = sharedInstance;
        instance.locationManager = [CLLocationManager new];
        instance.locationManager.delegate = instance;
        instance.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // you can use kCLLocationAccuracyHundredMeters to get better battery life
        instance.locationManager.pausesLocationUpdatesAutomatically = NO; // this is important

    return sharedInstance;

- (void)startUpdatingLocation
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];

    if (status == kCLAuthorizationStatusDenied)
        NSLog(@"Location services are disabled in settings.");
        // for iOS 8
        if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
            [self.locationManager requestAlwaysAuthorization];
        // for iOS 9
        if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
            [self.locationManager setAllowsBackgroundLocationUpdates:YES];

        [self.locationManager startUpdatingLocation];

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    CLLocation *mostRecentLocation = locations.lastObject;
    NSLog(@"Current location: %@ %@", @(mostRecentLocation.coordinate.latitude), @(mostRecentLocation.coordinate.longitude));

    NSDate *now = [NSDate date];
    NSTimeInterval interval = self.lastTimestamp ? [now timeIntervalSinceDate:self.lastTimestamp] : 0;

    if (!self.lastTimestamp || interval >= 5 * 60)
        self.lastTimestamp = now;
        NSLog(@"Sending current location to web service.");


@Myxtic 2015-03-03 15:27:08

Does this work for more than a few hours? It seems like even if the app is not terminated, the device stops pushing location updates after an hour or so of the app going to the background.

@Leszek Szary 2015-03-03 16:12:32

I got it working for 20 hours in background and did not notice any problems. Are you sure you did set everything like above?

@Myxtic 2015-03-03 16:56:46

Interesting. I have pausesLocationUpdatesAutomatically set to YES, but I'm guessing it should resume once I start moving again, which it does not seem to be doing. Do you have Background Fetch checked too, under Capabilities -> Background Modes?

@Leszek Szary 2015-03-03 17:27:33

Background Fetch is disabled in my project (it should not matter if it is off or on). However pausesLocationUpdatesAutomatically must be set to NO for above example to work properly. It will NOT resume automatically once you start moving again if it was paused by the system previously. That is why in above example I set this property to NO.

@Myxtic 2015-03-03 17:45:38

I think you are absolutely right. Found some more information about the issue here:

@Adrian Hoe 2015-04-22 04:06:03

Hi @LeszekS, I'm learning about background process and am also looking for similar example. Your solution is very close to what I'm looking for. I wonder how can I attach the LocationManager to a UIViewController or AppDelegate? I have no slightest idea how to execute the codes in your example. Can you please provide some ideas how to execute your codes? Thanks,

@Leszek Szary 2015-04-22 11:58:39

@AdrianHoe in your view controller just call [[LocationManager sharedInstance] startUpdatingLocation]; and location update will start working.

@Ganesh Somani 2015-09-02 03:37:45

Any specific reason why this should not work in iOS 7?

@Leszek Szary 2015-09-02 06:18:39

Did not test it on iOS 7 but probably it should also work fine.

@Leszek Szary 2015-09-29 06:17:05

Of course the code above is only the content of .m file. I assumed it will be obvoius that you also need to create an interface declaration in .h file to make it work. Also you must add declarations of sharedInstance and startUpdatingLocation methods in your interface (.h) file to be able to call it from AppDelegate.

@SMKS 2016-01-19 18:50:08

Is this the same for iOS9? Also, Is it possible to get location every 5 minutes while the app is terminated? Say, a service that starts automatically when the device is started?

@Fogmeister 2016-03-16 14:36:29

@SMKS that's not possible.

@Fenil 2016-06-09 14:52:50

@LeszekS you need to add below code for iOS 9 support for background - if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpda‌​tes:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }

@yerpy 2017-02-09 13:57:42

@LeszekS from where are you taking lastTimestamp ?

@Honey 2017-07-20 15:56:00

What's the convenience of doing this? You're still draining the battery by having a constant high accuracy. The only thing you don't do is you don't actually use the already received location until you reach an interval of 5 minutes...

@Leszek Szary 2017-07-20 17:28:25

@Honey yes you are absolutely right about battery life, but still I can see reasons why someone would need only 1 location reading per x minutes and that was the question asked here so above code is the answer to this question. I also mentioned in the comment above that kCLLocationAccuracyHundredMeters can be used for better battery life.

@Dhanunjay Kumar 2017-11-10 09:13:56

@LeszekS : please let me know how to get current location even though app is killed or terminated , i have tried using significantlocation but didn't work?

@sash 2016-10-29 14:40:56

There is a cocoapod APScheduledLocationManager that allows to get background location updates every n seconds with desired location accuracy.

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)

The repository also contains an example app written in Swift 3.

@Moxarth 2017-07-06 10:46:52

do you have anything like this in objective c ?

@nickfox 2014-02-04 02:45:15

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:

locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
locationManager.distanceFilter = 5;

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:

locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter = 0;

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.

@Hardik Darji 2014-03-12 14:02:32

I tried your solution, but is not working... when app goes to background then, even after increase accuracy, app does not gettign called didUpdateToLocation method in my case

@nickfox 2014-03-13 01:20:53

@HardikDarji important question. Are you moving? If not, location updates may stop. Try taking your phone out for a walk or a drive and see if that fixes it.

@Hardik Darji 2014-03-13 05:36:47

Thanks for your quick response. But I want location updates in every 2 min, without care of my phone is moving or not. In this scenario didUpdateToLocation method is not called. I am looking here for : How do I get location update every n minutes !!!

@nickfox 2014-03-13 07:10:18

try setting the timeIntervalInSeconds to 120 and uncomment this line: locationManager.pausesLocationUpdatesAutomatically = NO;

@Hardik Darji 2014-03-13 11:36:46

I also tried with locationManager.pausesLocationUpdatesAutomatically = NO; aslo set Location_Update_Interval = 120. I am calling reduceTrackingAccuracy method, in locationManager:didUpdateLocations delegate, and also schedule for calling increaseTrackingAccuracy method after delay of 115 seconds. increaseTrackingAccuracy is calling, but after increase accuracy, locationManager:didUpdateLocations delegate method is not getting called..

@Hardik Darji 2014-03-13 14:15:40

its working nick !!! if i am not moving, but move with minimum distance filter, its getting called locationManager:didUpdateLocations method. thanks:)

@samfr 2015-05-03 01:31:13

does the solution you posted in the above comment kill the battery life, or are you still doing some optimization for that?

@wjans 2011-06-24 08:32:56

I found a solution to implement this with the help of the Apple Developer Forums:

  • Specify location background mode
  • Create an NSTimer in the background with UIApplication:beginBackgroundTaskWithExpirationHandler:
  • When n is smaller than UIApplication:backgroundTimeRemaining it will work just fine. When n is larger, the location 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.

@utahwithak 2011-09-08 21:31:25

do you happen to have the link to the forum. I'm looking to implement the same type of location mapping and haven't been able to get it to work. Or some sample code would be greatly appreciated.

@saurabh 2012-01-03 06:14:00

Can you please explain why the background task is not killed after 10 mins (maximum allowed time) if you just stop and start the location manager? is it some sort of intended functionality? it sounds more like a bug in Apple SDK if it happens like that. Which iOS version you were trying it on?

@wjans 2012-01-04 09:08:48

@cwieland: The forum post doesn't mention any more information but all individual "steps" are clearly explained in the Apple docs. In case you run into specific problems, I suggest you post your own question.

@wjans 2012-01-04 09:09:16

@saurabh: As per my understanding, it works as designed since location updates is a valid background processing mode. It does work on different iOS versions (4.X, 5.X), don't think it's a bug.

@subharb 2012-01-25 09:19:44

If n is larger than 10 mins(which is the extra time the iOs gives you) you will end up sending the coordinates after that 10 mins, as you said, "in case n is larger, the location manager should be enabled (and disabled) " wich produces "didUpdateLocation" to execute. Im sure it works for you but could you post some code so I can get a better picture of what you did?, this EXACTLY what Im looking for.

@wjans 2012-01-26 18:40:24

@DavidShaikh: I literally implemented it like this: [self.locationManager startUpdatingLocation]; [self.locationManager stopUpdatingLocation];. In didUpdateToLocation I just check whether or not I'm interested in the update.

@deimus 2012-02-22 07:31:01

@wjans I'm not getting your solutions ... If I get you right you are running NSTimer in beginBackgroundTaskWithExpirationHandler scheduling to startUpdateLocation every n minutes right ? But what you do if n is larger than backgroundTimeRemaining ? Where do you enable and disable locationManager ? Shall the NSTimer work at all if n > backgroundTimeRemaining ???

@wjans 2012-02-22 17:35:47

@deimus: No, that's right. In case n is larger, scheduling a timer every n minuties won't work. Therefor you have to make sure to enable it sooner, before backgroundTimeRemaining becomes zero.

@deimus 2012-02-22 18:16:33

@wjans I'm really cluttered in your solution ... just couple of my questions 1. Has your code ever worked for you if n is larger than backgroundTimeRemaining ? 2. How you have used NSTimer with UIApplication:beginBackgroundTaskWithExpirationHandler: particularely i'm insterested how you have scheduled NSTimer ?

@wjans 2012-02-22 18:46:31

@deimus: 1. Yes, by enabling and immediately disabling the location mgr as described. 2. When using UIApplication:beginBackgroundTaskWithExpirationHandler, you specificy a block of code to be executed. In that block, you can simply start a timer as described in the Apple documentation.

@deimus 2012-02-22 18:50:35

@wjans I'm really interested only in case when n is larger than backgroundTimeRemaining... I guess NSTimer will not work work... you suggested to enable it sooner ... actually no one knows when user will send application to background ... what do you mean under "sooner" ?

@deimus 2012-02-22 19:18:49

@wjans let say n is 14 mins and backgroundTimeRemaining is 10 mins ... Can you please describe the workflow of you code. When NSTimer will fire the scheduled method, starting from the point when application goes to background.

@deimus 2012-02-22 20:35:11

Finally after more than hour of thinking got the code working... I simply couldn't understand why the background task was not killed after 10 mins (backgroundTimeRemaining) ... as also @saurabh mentioned in his comment ... So my last question to you, have your app passed Apple submission, this is not the violation of app acceptance guideline ?

@Hrushikesh Betai 2012-02-24 06:01:48

@wjans can anybody provide me the sample code for that Background process work flow at a time. i get location at particular time. not at a didupdatelocation method. i really need to work out as the asked question

@user836026 2012-03-01 11:45:12

I wonder if anybody could post the code. also as demus asked. did this pass Apple submission .

@wjans 2012-03-01 18:51:11

@all: Yes, our app is available in the AppStore. I am not gonna post all the code, all mentioned bulletpoints are clearly documented features. In case you are having a specific problem, post your own question explaining what you have tried and what goes wrong.

@user836026 2012-03-01 20:43:20

Yes,I tested it & it works as you described. Basically if you started " [locationManager startUpdatingLocation];" in "beginBackgroundTaskWithExpirationHandler" it works forever, it doesn't stop as excepted. I'm just worried that this could be a bug and Apple might fix it in future.

@wjans 2012-03-06 19:04:20

@user836026: If you don't stop the location manager, your app won't be terminated. That works as designed. In my scenario, I stop the location manager.

@user836026 2012-03-08 10:17:57

@wjans do you mean by "Specify location background mode" to set UIBackgroundModes=location in Info.plist file?

@htafoya 2012-03-10 20:29:10

Works nice, however I don't like very much that the user is prompted to allow user location. Any way thanks :).

@user836026 2012-03-12 17:49:44

So correct me if i'm wrong. for this to work, you need to start/stop location update "every 10 minutes".

@wjans 2012-03-14 20:29:30

@user836026: Yes, that's what I mean by specifying background mode. After stopping the location update, it should be started again within 10 minutes to avoid the app from being terminated.

@user836026 2012-03-15 07:59:50

@wjans, it works fine now with me ... just for fine tuning, I only turn on location update for short period of time - only 2 seconds - to save battery. do you think 2 seconds is OK, or too short to get high accuracy location update.

@Luka 2012-03-15 14:06:11

do you guys have any test of the battery consumption of this method?

@user836026 2012-03-17 17:15:35

this compared to "always On" location update is much better, i didn't notice battery leaking. However, I didn't do through testing.

@Luka 2012-03-20 10:47:59

on my test there is not such a difference. I've done a test comparing: my code with this method, mylocus (on appStore) and the "always On" method.

@user836026 2012-05-11 18:16:10

@luka: do you know how mylocus app works? does it use background location update or significant change only?

@Luka 2012-05-12 11:21:05

it think (I haven't seen the implementation of course) it uses background location update + NSTimer

@user836026 2012-05-12 17:23:41

Did you test mylocus app? does it drain battery, or there is no noticable effect on battery.

@Ajay Sharma 2012-06-12 18:17:16

@wjans hey .. .can you post your code somewhere as if I am also looking for similar things.Thanks

@Lolo 2013-03-01 05:30:38

For all those interested in seeing some actual code reflecting what is being discussed here, check…

@sash 2013-09-23 15:28:53

there is some problem with this approach on iOS 7, take a look at…

@SleepNot 2014-07-14 05:54:28

Anyone figured out how to use a larger interval than the background task?

@Yash 2014-12-08 12:13:20

@All which solution this or below samthui7's explained solution should I prefer to save the device battery or both will affect the same? And can these both solutions will work on iOS 7 and iOS 8?

@AmitP 2015-03-06 13:32:07

Here's a great location framework for iOS that does it all for you:

@user6539552 2017-06-01 12:53:20

Can anyone share the code regarding this solution? Is that the timer start, and every time it trigger and check the value of n to toggle the state of the LocationManager? If it is the case, how can we avoid the timer being killed when the app is at the background?

@Avijit Nagare 2019-01-09 15:28:26

@wjans. WhenInUse service user moves from online to offline will it return correct coordinates ? till what time? if user offline is it good idea to call "StartUpdatingLocation" if user moving?

@dor506 2019-01-20 09:15:55

@wjans How do you remove the status bar location icon during the "cooldown" (betweeen the stopUpdatingLocation to the next startUpdatingLocation)? It stays there even after the calling to stopUpdatingLocation. The icon is only get disappeared after explicitly calling stopUpdatingLocation (from a ViewController or something like that)

@hmitkov 2016-07-06 13:36:42

Here is what I use:

import Foundation
import CoreLocation
import UIKit

class BackgroundLocationManager :NSObject, CLLocationManagerDelegate {

    static let instance = BackgroundLocationManager()
    static let BACKGROUND_TIMER = 150.0 // restart location manager every 150 seconds
    static let UPDATE_SERVER_INTERVAL = 60 * 60 // 1 hour - once every 1 hour send location to server

    let locationManager = CLLocationManager()
    var timer:NSTimer?
    var currentBgTaskId : UIBackgroundTaskIdentifier?
    var lastLocationDate : NSDate = NSDate()

    private override init(){
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
        locationManager.activityType = .Other;
        locationManager.distanceFilter = kCLDistanceFilterNone;
        if #available(iOS 9, *){
            locationManager.allowsBackgroundLocationUpdates = true

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.applicationEnterBackground), name: UIApplicationDidEnterBackgroundNotification, object: nil)

    func applicationEnterBackground(){

    func start(){
        if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){
            if #available(iOS 9, *){
            } else {
        } else {
    func restart (){
        timer = nil

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        switch status {
        case CLAuthorizationStatus.Restricted:
            //log("Restricted Access to location")
        case CLAuthorizationStatus.Denied:
            //log("User denied access to location")
        case CLAuthorizationStatus.NotDetermined:
            //log("Status not determined")
            if #available(iOS 9, *){
            } else {
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

            // The locations array is sorted in chronologically ascending order, so the
            // last element is the most recent
            guard let location = locations.last else {return}

            let now = NSDate()
                //TODO: Every n minutes do whatever you want with the new location. Like for example sendLocationToServer(location, now:now)

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {


    func isItTime(now:NSDate) -> Bool {
        let timePast = now.timeIntervalSinceDate(lastLocationDate)
        let intervalExceeded = Int(timePast) > BackgroundLocationManager.UPDATE_SERVER_INTERVAL
        return intervalExceeded;

    func sendLocationToServer(location:CLLocation, now:NSDate){

    func beginNewBackgroundTask(){
        var previousTaskId = currentBgTaskId;
        currentBgTaskId = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
            FileLogger.log("task expired: ")
        if let taskId = previousTaskId{
            previousTaskId = UIBackgroundTaskInvalid

        timer = NSTimer.scheduledTimerWithTimeInterval(BackgroundLocationManager.BACKGROUND_TIMER, target: self, selector: #selector(self.restart),userInfo: nil, repeats: false)

I start the tracking in AppDelegate like that:


@user921509 2016-12-19 15:55:24

Thanks. Our project needs to track user location + send PubNub events in the background and your solution is working really well.

@AmanGupta007 2017-06-21 01:52:55

Hi Hmitkov, Where I Can Call sendLocationToServer method to send user location on server

@hmitkov 2017-06-26 11:28:22

@AmanGupta007 You can call sendLocationToServer in func locationManager(manager: didUpdateLocations:). Notice the //TODO comment in the code.

@DookieMan 2017-07-28 15:41:45

@hmitkov Is it possible to start and stop Location Services with this while app is in the background? Example, start location service from a push notification grab some lat/long, send to webservice, then stop updating location. Do this each time the 'content-available' = 1 is included in the push body.

@hmitkov 2017-07-31 06:55:40

@DookieMan You don't need to do it this way. The purpose of the code above is to keep the app alive in the background at all times. While in your case you don't need your app to stay active in the background. When your app receives a PN with 'content-available' = 1, it is automatically activated in the background and the method application.didReceiveRemoteNotification is called. All you need to do inside that method is to start the location manager for a fresh location update, send it to your server and call the completion handler.

@Tom 2018-08-15 11:34:20

I've tried this code but it seems like it's not working on iOS11? (I haven't test it on any other versions.)

@Dipendra Sharma 2019-12-11 18:39:45

Is it working on ios 13?

@Nilesh 2016-01-13 06:48:34

if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    [self.locationManager setAllowsBackgroundLocationUpdates:YES];

This is needed for background location tracking since iOS 9.

@Yaro 2016-02-14 16:49:59

This saved my day! using iOS8 deployment target, with iOS9 device

@samthui7 2014-07-09 11:36:34

I did write an app using Location services, app must send location every 10s. And it worked very well.

Just use the "allowDeferredLocationUpdatesUntilTraveled:timeout" method, following Apple's doc.

What I did are:

Required: Register background mode for update Location.

1. Create LocationManger and startUpdatingLocation, with accuracy and filteredDistance as whatever you want:

-(void) initLocationManager    
    // Create the manager object
    self.locationManager = [[[CLLocationManager alloc] init] autorelease];
    _locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    _locationManager.desiredAccuracy = 45;
    _locationManager.distanceFilter = 100;
    // Once configured, the location manager must be "started".
    [_locationManager startUpdatingLocation];

2. To keep app run forever using allowDeferredLocationUpdatesUntilTraveled:timeout method in background, you must restart updatingLocation with new parameter when app moves to background, like this:

- (void)applicationWillResignActive:(UIApplication *)application {
     _isBackgroundMode = YES;

    [_locationManager stopUpdatingLocation];
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [_locationManager setDistanceFilter:kCLDistanceFilterNone];
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    [_locationManager startUpdatingLocation];

3. App gets updatedLocations as normal with locationManager:didUpdateLocations: callback:

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
//  store data
    CLLocation *newLocation = [locations lastObject];
    self.userLocation = newLocation;

   //tell the centralManager that you want to deferred this updatedLocation
    if (_isBackgroundMode && !_deferringUpdates)
        _deferringUpdates = YES;
        [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10];

4. But you should handle the data in then locationManager:didFinishDeferredUpdatesWithError: callback for your purpose

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {

     _deferringUpdates = NO;

     //do something 

5. NOTE: I think we should reset parameters of LocationManager each time app switches between background/forground mode.

@Yash 2014-12-08 12:12:03

@All which solution this or above wjans's explained solution should I prefer to save the device battery or both will affect the same?

@samthui7 2015-04-16 04:15:25

I did try both solutions you mention, and saw that @wjans's one is a little bit more save battery. But, after the coming of iOS 8, it seems that that solution does not work properly anymore. For more detail: most of time, app cannot have long live in background mode.

@CedricSoubrie 2016-09-13 09:21:16

@samthui7 Why do you set pausesLocationUpdatesAutomatically = false ?

@samthui7 2016-09-13 10:21:39

My app's requirement is to keep sending userLocation every 10s, while pausesLocationUpdatesAutomatically = true tells location manager to pause updates if there is seemly no location change (Apple's doc). Anyway, I did not explicitly test the case of location manager pauses updates yet :D.

@samthui7 2016-10-28 01:47:33

@CedricSoubrie: Setting pausesLocationUpdatesAutomatically = true causes my app to stop updating location.

@Amit Shelgaonkar 2015-06-30 17:52:11

It seems that stopUpdatingLocation is what triggers the background watchdog timer, so I replaced it in didUpdateLocation with:

     [self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
     [self.locationManager setDistanceFilter:99999];

which appears to effectively power down the GPS. The selector for the background NSTimer then becomes:

- (void) changeAccuracy {
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];

All I'm doing is periodically toggling the accuracy to get a high-accuracy coordinate every few minutes and because the locationManager hasn't been stopped, backgroundTimeRemaining stays at its maximum value. This reduced battery consumption from ~10% per hour (with constant kCLLocationAccuracyBest in the background) to ~2% per hour on my device

@eharo2 2014-08-25 22:59:44

Attached is a Swift solution based in:

Define App registers for location updates in the info.plist

Keep the locationManager running all the time

Switch kCLLocationAccuracy between BestForNavigation (for 5 secs to get the location) and ThreeKilometers for the rest of the wait period to avoid battery drainage

This example updates location every 1 min in Foreground and every 15 mins in Background.

The example works fine with Xcode 6 Beta 6, running in a iOS 7 device.

In the App Delegate (mapView is an Optional pointing to the mapView Controller)

func applicationDidBecomeActive(application: UIApplication!) {
    if appLaunched! == false { // Reference to mapView used to limit one location update per timer cycle
        appLaunched = true
        var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        var window = appDelegate.window
        var tabBar = window?.rootViewController as UITabBarController
        var navCon = tabBar.viewControllers[0] as UINavigationController
        mapView = navCon.topViewController as? MapViewController

func applicationDidEnterBackground(application: UIApplication!) {
    self.startInitialPeriodWithTimeInterval(15 * 60.0)

func startInitialPeriodWithTimeInterval(timeInterval: NSTimeInterval) {
    timer?.invalidate() // reset timer
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getFirstLocationUpdate:"), userInfo: timeInterval, repeats: false)

func getFirstLocationUpdate(sender: NSTimer) {
    let timeInterval = sender.userInfo as Double
    mapView?.canReportLocation = true
    timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("waitForTimer:"), userInfo: timeInterval, repeats: true)

func waitForTimer(sender: NSTimer) {
    let time = sender.userInfo as Double
    locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
    finalTimer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: Selector("getLocationUpdate"), userInfo: nil, repeats: false)

func getLocationUpdate() {
    mapView?.canReportLocation = true

In the mapView (locationManager points to the object in the AppDelegate)

override func viewDidLoad() {
    var appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate
    locationManager = appDelegate.locationManager!
    locationManager.delegate = self
    canReportLocation = true

  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        if canReportLocation! {
            canReportLocation = false
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
        } else {
            //println("Ignore location update")

@Bushra Shahid 2011-06-24 09:50:03

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 key UIBackgroundModes in your app's info.plist. Now, what you need to do is start the location updates anywhere in your app:

    CLLocationManager locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;//or whatever class you have for managing location
    [locationManager startUpdatingLocation];

Next, write a method to handle the location updates, say -(void)didUpdateToLocation:(CLLocation*)location, in the app delegate. Then implement the method locationManager:didUpdateLocation:fromLocation of CLLocationManagerDelegate 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:

NSDate *newLocationTimestamp = newLocation.timestamp;
NSDate *lastLocationUpdateTiemstamp;

int locationUpdateInterval = 300;//5 mins

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (userDefaults) {

        lastLocationUpdateTiemstamp = [userDefaults objectForKey:kLastLocationUpdateTimestamp];

        if (!([newLocationTimestamp timeIntervalSinceDate:lastLocationUpdateTiemstamp] < locationUpdateInterval)) {
            //NSLog(@"New Location: %@", newLocation);
            [(AppDelegate*)[UIApplication sharedApplication].delegate didUpdateToLocation:newLocation];
            [userDefaults setObject:newLocationTimestamp forKey:kLastLocationUpdateTimestamp];

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

@wjans 2011-06-24 11:43:30

That way the location services are constantly enabled (indeed battery draining), I don't want that. I want to enable the location service every n minutes and immediately disable it when I have a good fix (just noticed that I didn't explain that clearly in my question). I can achieve this behaviour in the solution I described.

@knagode 2013-03-27 00:49:58

You can set location manager accuracy to 1km - this will leave your battery almost intact. After 5min you set accuracy to 1m. When you get satisfying location (normally after 5s) just set accuracy back to 1km.

@Hardik Darji 2014-03-12 06:32:02

knagode, I tried your suggested solution for battery draining issue, but even after increase accuracy after N minutes, locationManager: didUpdateLocations method is not called again. I tried startUpdating and stopUpdating, instead of increase and decrease accuracy, it is called successfully delegate locationManager: didUpdateLocations method, after N minutes, but is not working in Background MODE...

@Honey 2017-07-28 14:30:53

As for the links of documentation. See here: "The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread."

@HelmiB 2013-06-01 11:11:29

To someone else having nightmare figure out this one. I have a simple solution.

  1. look this example from> have sample code, this works perfectly, but unfortunately no timer during background location. this will run indefinitely.
  2. Add timer by using :

    -(void)applicationDidEnterBackground {
    [self.locationManager stopUpdatingLocation];
    UIApplication*    app = [UIApplication sharedApplication];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
     self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
  3. Just don't forget to add "App registers for location updates" in info.plist.

@SleepNot 2014-07-14 05:55:50

Does this get the location for more than 3 minutes?

@Sergio Andreotti 2015-12-03 08:53:24

Must set location in Capabilities -> Background Mode.

@Kirti 2016-09-22 06:50:12

It's not working!! ?I have checked on iOS 8 ans iOS 10

@Honey 2017-08-18 13:07:45

Correct me if I'm wrong. Based on what I read, you start locationManager only once. After that all intervals are redundant. Since it's already been started

@anshuman burmman 2019-08-03 13:29:30

it is working but it is getting stopped after 170 seconds. i want to run my task in background for unlimited time

@Alejandro Luengo 2012-09-24 11:13:43

Now that iOS6 is out the best way to have a forever running location services is...

- (void)applicationWillResignActive:(UIApplication *)application
 Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
 Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.

NSLog(@"to background");

app.isInBackground = TRUE;

UIApplication *app = [UIApplication sharedApplication];

// Request permission to run in the background. Provide an
// expiration handler in case the task runs long.
NSAssert(bgTask == UIBackgroundTaskInvalid, nil);

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    // Synchronize the cleanup call on the main thread in case
    // the task actually finishes at around the same time.
    dispatch_async(dispatch_get_main_queue(), ^{

        if (bgTask != UIBackgroundTaskInvalid)
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Do the work associated with the task.

    locationManager.distanceFilter = 100;
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    [locationManager startMonitoringSignificantLocationChanges];
    [locationManager startUpdatingLocation];

    NSLog(@"App staus: applicationDidEnterBackground");
    // Synchronize the cleanup call on the main thread in case
    // the expiration handler is fired at the same time.
    dispatch_async(dispatch_get_main_queue(), ^{
        if (bgTask != UIBackgroundTaskInvalid)
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;

NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);


Just tested it like that:

I started the app, go background and move in the car by some minutes. Then I go home for 1 hour and start moving again (without opening again the app). Locations started again. Then stopped for two hours and started again. Everything ok again...

DO NOT FORGET USING the new location services in iOS6

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    CLLocation *loc = [locations lastObject];

    // Lat/Lon
    float latitudeMe = loc.coordinate.latitude;
    float longitudeMe = loc.coordinate.longitude;

@Ken 2012-09-28 15:18:52

If the app crashes or is killed, the system doesn't restart, right?

@axello 2012-10-01 15:42:29

For more readable code, you can do a [locations lastObject]; instead of the [locations objectAtIndex:[locations count] - 1]

@pengwang 2012-11-23 06:36:38

your method is only at ios6?

@nithinreddy 2013-01-16 10:05:11

Do we have to use this? I thought just have the location manager code in viewDidLoad of a class, and have set a background key in the plist file that the app registers for Location updates should be good enough? Can you please help me with this!

@Alejandro Luengo 2013-01-17 12:34:32

Yes, it will work like charm nithinreddy but it will stop working after 10 minutes since iOS kills long threads after that period. My solution is perfect if you want to have those services started forever. I made some tests two days ago and it drains 6% battery each hour. Using [locationManager startUpdatingLocation] instead will drain 17%

@Jonathan 2013-02-08 00:32:34

When using your code, I need to move the [locationManager startUpdatingLocation]; call to be outside of the dispatch_async() block (so it ends up between the bgTask and dispatch_async()). Otherwise I won't receive any location updates (locationManager: didUpdateLocations:). Am I doing something wrong?

@Alejandro Luengo 2013-02-08 11:04:48

@Jonathan have you enabled location services on background? Please check your plist file. My code should work without modification. I have used it on two apps

@Jonathan 2013-02-08 14:52:59

@AlejandroLuengo Yeah, my plist file is right. I have a class that manages the location updates. In the applicationWillResignActive: method in my AppDelegate I call a method from this class, to start the updates. When using the first startUpdatingLocation: call, everything works (forever). However, when using the second call (as in your example), location updates stop after ten minutes. Thanks!

@Alejandro Luengo 2013-02-10 19:10:53

@Jonathan please note you must add this interface on the code where do receive locationManager updates. (@)interface AppDelegate : UIResponder <UIApplicationDelegate> + (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations; (@)end Also you need TWO location methods: one for regular updates and one for bg updates, like this: - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations and - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation

@Alejandro Luengo 2013-02-10 19:11:29

@Jonathan send me an email if you want more help. I will be glad helping you. You can reachme at website, find contact. I don't want to put the email here to avoid spam spiders

@Sharme 2013-04-04 07:02:04

@AlejandroLuengo thanks for your answer. I am doing an ios app which tracks user locations. I need to send the new location co ordinates to the server every 30 seconds and need to update the location again once I get response from the server. The problem is sometimes didUpdateToLocation is not called and in that method only I am sending request to the server. I am really helpless here. Do you have any suggestion ? If you have, let me know.

@Alejandro Luengo 2013-04-04 09:35:53

didUpdateToLocation only gets called when location changes. You should send the last location received every 30 seconds since if you don't move you won't receive a new location

@fjlksahfob 2013-04-11 22:04:18

I'm not sure how this is any different from enabling significant change monitoring by itself. That's supposed to wake your app up and make it monitor location changes when you move 500m+ (which sounds like what you did). The rest seems kind of meaningless to me. Am I missing something?

@Chazbot 2011-06-14 17:48:26

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 call locationManager: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 the newLocation 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.

@wjans 2011-06-15 06:00:05

There are apps available in the AppStore (like for instance "My Locus") that do make it possible to get a location update in the background. They don't keep the location service active but it just gets enabled shortly as per the interval defined. How do they do this?

@Chazbot 2011-06-15 15:31:04

In the situation you describe, the app is most likely using the startMonitoringSignificantLocationChanges approach. Here, the phone gets temporarily 'woken up' when it receives a location update, but there's no interval that you can set to 'ping' this service in the background. When the phone moves (or switches from Cellular to GPS or to Wifi), it triggers an update. The Stanford iTunes U lecture on the topic was really helpful for me - hopefully it can help you find a workaround:‌​…

@wjans 2011-06-17 05:15:05

Thx for the pointer. However, I still don't understand what the app is doing though. Even if my phone is at my desk, not moving at all, I can see the location service being triggered every 10 minutes (exactly). If I understand correctly, startMonitoringSignificantLocationChanges wouldn't give any update in that case.

@user836026 2012-05-11 20:06:08

@wjans how is your phone battery consumption, did you notice it drain quicly maybe due to Mylocus app?

Related Questions

Sponsored Content

9 Answered Questions

1 Answered Questions

[SOLVED] Working with location updates when app is terminated

3 Answered Questions

[SOLVED] Send location updates every 30 minutes in Swift

3 Answered Questions

2 Answered Questions

[SOLVED] Repeating a task every x seconds while running in background

  • 2016-04-04 14:21:19
  • davis
  • 114 View
  • 0 Score
  • 2 Answer
  • Tags:   ios objective-c

3 Answered Questions

1 Answered Questions

[SOLVED] Location update in background mode only 10 min

  • 2015-09-16 15:14:16
  • Ecroo
  • 949 View
  • 3 Score
  • 1 Answer
  • Tags:   ios objective-c

1 Answered Questions

[SOLVED] How to execute a background task every 15 minutes?

3 Answered Questions

[SOLVED] How to run application in background mode forever?

Sponsored Content