Background Location Update Programming for iOS 7 and iOS 8

Before iOS 7, I used some location update solutions found from stackoverflow. After the iOS 7 is released, the location update (especially on background) is not working well in iOS 7. There are many existing location based apps had the same problem. It was due to the background services in iOS 7 which kill the app when the app is in suspended state.

After a few weeks of trial and error in experimenting many different solutions, I finally found one solution that works well for the app that I need to develop.

Note: The solution might not be elegant. It works well for what I want to create. When I am free, I am still constantly looking for more elegant solutions by exploring the background services in iOS 7.

iOS Application States and Multitasking

Before I dig deeper into the location services, I would like to share a bit on the iOS app states. It is very important for iOS 7 and above because we have multitasking background services starting from this version.

iOS App States

 

There are basically 5 states:-
1. Inactive – The app is running on foreground but there is no activity at the moment.
2. Active – The app is running on foreground and there are some activities.
3. Background – The app is on the background and still executing code. The app can move to suspended mode anytime now. But, the app can request extra time in executing code for a short period of time.
4. Suspended – The app is on the background and not executing code. Normally, the system will move app from background mode to this state automatically without any notification. But the app is still in memory.
5. Not running – The app is either not running or has been terminated by the system during low memory condition.

Most of the solutions before iOS 7 work well because during that time the system does not have multitasking and the system does not automatically move the app from background mode to suspended mode.

So, if your app needs consistent location update from the device, you will have to implement a solution that constantly refresh the app when it is in background mode so that it has a short period of time in executing the code and send the location to your server.

For more information on App States and Multitasking, you can visit: Guidelines by Apple on App States and Multitasking.

Background Location Update Programming for iOS 7

Behaviour of the location service that the app I have to develop:-
1. During the normal time, the app has to send the location to the server every 3 minutes.
2. When the user is running event, the app has to send location to the server every 1 minute.
3. The location has work both in foreground and background.

So, this app will get the location from the phone all the time. I have tested many solutions and the solution below works exactly as I needed and it consumes about 5% of battery per hour.

First of all, if you are using storyboard, you will have to make sure that “location update” under the Background Modes is enable. Screen shot as below:-
iOS 7 Location Background Mode This is very important as without that your app will not be able to get location when it is in background.

I created a class just to handle the location service. The most important function from the locationManager delegate is didUpdateLocations. You will need to know how to handle this function properly. I have programmed to make the locationManager restarts every 1 minute. When the locationManager is started, it will only last for 10 seconds to receive locations update from the device. So basically, the location Manager is only turned on for 10 seconds for 60 seconds.

I have tested on my device and it only consumes about 5-6% of battery every hour. The most important function is listed below with some explanation.

Updated on February 2014: Added the solution on Github and post to the thread in stackoverflow.

Updated on April 2014: EC has found a fix for the location update for an extended period of time.

Updated on May 2014: I received some requests by some developers (through email contact and the comment area of this post) on the sample codes for sending the locations to server on a certain time interval. I have added the sample codes and I have integrated EC’s fix on BackgroundTaskManager.m too. Full Solution: Background Location Update for iOS 7 with Location Update to Server.

Updated on September 2014: I have updated the solution to work in iOS 8. A new key NSLocationAlwaysUsageDescription has been added to the PList. It is a requirement in iOS 8 to inform the users on the reasons you need the location update from their devices. [locationManager requestAlwaysAuthorization]; has to be called in iOS 8 as well when getting the location.

Getting Location Updates for iOS 7 and 8 when the App is Killed/Terminated/Suspended

I have promised to write an article related to getting Location Updates for iOS 7 and 8 when the App is Killed/Terminated/Suspended. I have had a busy development schedule in the last few months until the New Year Holiday break. Finally, I have time to write the articles and post the solution on Github.

Please read this article for more details: Getting Location Updates for iOS 7 and 8 when the App is Suspended.

Market Share for iOS 7
How to Use Container View Controller

Comments

  1. Torin Nguyen says:

    Great article & source code.
    I’ve looked through the entire of your source code, and fully understood your LocationTracker & LocationShareModel classes.
    But I wonder what is the responsibility of BackgroundTaskManager class?
    Where is the correct place to insert the code to update location to server?
    Thanks for your response.

    • Hi Torin,

      I am glad that I am able to help. BackgroundTaskManager is used to handle all the background tasks that are needed for the location. This is especially needed when you are dealing with multithreading with multi instances of locationManager. BackgroundTaskManager will create/end the correct background tasks accordingly.

      As for sending the location to server, you can create a new function in LocationTracker class or anywhere else that has the shareModel. More importantly is you have to use the same shareModel and choose the best location from myLocationArray and send to server. Remember to clear this array after sending the best location to server.

      • Hi, How are you ?

        I am glad to meet you at this article.

        I used your code fully for location tracking at background mode.

        It work well, but I got one issue.

        I am not sure what the issue it now.

        I want to solve the problem asap. I hope for your advise.

        Thanks

        Daniel

        name”:”Ultrack GTS”,”bug_type”:”109″,”os_version”:”iPhone OS 7.1.2 (11D257)”,”bundleID”:”ultrack.ca.gtstrackerv1″,”version”:”1.0.3 (1.0)”,”app_name”:”Ultrack GTS”} Incident Identifier: 53048A32-8541-47E8-AC93-730C73130ED1
        CrashReporter Key: 29469c418f2d8a32763489d05329eab8bb7f760f
        Hardware Model: iPhone4,1
        Process: Ultrack GTS [32288]
        Path: /var/mobile/Applications/77121190-6221-496E-AF77-138700CFBFE2/Ultrack GTS.app/Ultrack GTS
        Identifier: ultrack.ca.gtstrackerv1
        Version: 1.0.3 (1.0)
        Code Type: ARM (Native)
        Parent Process: launchd [1]

        Date/Time: 2014-10-16 15:58:00.489 -0400
        OS Version: iOS 7.1.2 (11D257)
        Report Version: 104

        Exception Type: 00000020
        Exception Codes: 0x000000008badf00d
        Highlighted Thread: 2

        Application Specific Information:
        Ultrack GTS[32288] has active assertions beyond permitted time:
        {(
        identifier: Called by Ultrack GTS, from -[BackgroundTaskManager beginNewBackgroundTask] process: Ultrack GTS[32288] permittedBackgroundDuration: 180.000000 reason: finishTask owner pid:32288 preventSuspend preventIdleSleep preventSuspendOnSleep ,
        identifier: Called by Ultrack GTS, from -[BackgroundTaskManager beginNewBackgroundTask] process: Ultrack GTS[32288] permittedBackgroundDuration: 180.000000 reason: finishTask owner pid:32288 preventSuspend preventIdleSleep allowIdleSleepOverrideEnabled preventSuspendOnSleep )}

        • I alos have this error log and then app was aborted by system. How about Ricky??

          • Please double check your PList if the background location service is enable or not. Please triple check on the new requirements for iOS 8 and make sure the key for iOS 8 is there on the PList as well.

          • Hi, Ricky. I’m sure the background location service enabled. My app has successfully working on background about one day, But then system log report this below and abort my app.
            ” , from -[BackgroundTaskManager beginNewBackgroundTask] process: MarketingClient[75619] permittedBackgroundDuration: 40.000000 reason: finishTaskAfterBackgroundContentFetching owner pid:75619 preventSuspend preventIdleSleep preventSuspendOnSleep

          • Make sure Background App Refresh is On as well. Most likely it is that problem.

          • Background App Refresh absolutely. If it disable, my app will exit in half hour.The issue i think it does’t belongs to my app.

  2. This is a great solution to a problem that shouldn’t be so complicated. According to iOS 7.1 we should be able to get the user location even when the app is closed, but we have been having a real hard time accomplishing that. Do you have any insight into how you can modify your code to achieve this? We really appreciate this post and all of your time spent tackling this issue.

    • Hi JJMIAS, Thanks for stepping by. What do you mean by getting the location when the app is closed? You mean when the app is not even on the background?

      I think the solution, that I have provided, is still working fine on iOS 7.1. But, I would have to test more in order to double confirm about it.

      • Yes, I mean when the app is not even in the background. According to iOS7.1 there is a way to ‘launch’ the app from closed/swiped away and into memory for location updates. Someone even posted to your StackOverflow response on this code that:

        “We at KitLocate provides an sdk that allows you to get the user location even when the app is in the background (and in ios 7.1 even when the app is closed).”

        Ultimately I need a way (that isn’t a paid SDK) to get location updates for a user when their app is not launched just as Apple’s Find My Friends, Glympse and Life360 does.

        Thanks for your time and response.

        • I see. I haven’t do too much research into iOS 7.1 yet. I just checked the release note for iOS 7.1. There are a lot of changes on MapKit. Could it be the API is from the Mapkit itself? As for now, I only use Google Map for iOS. I guess it is probably the time for me to learn Apple MapKit.

          After submitting the app that I have been working for 2 months to the appstore, I will have more free time next week. I will do research into iOS 7.1 and I will see if I am able to find a better solution. I hope that I can come out with a more elegant solution that consumes less battery. If I found, I will post here and also to the StackOverFlow.

      • Hi ,I implemented this technique but my app is crashing background mode in iOS 7.1. Is there any solution?

        • I am using iOS 7.1 as well but most of the time my app is running fairly well. Only once in a while, it has inconsistent issue when the iOS decides to terminate the location update in the background. I didn’t know what is the exact reason. I am in contact with a few other developers who are using the solution that I provided. They have faced the inconsistent issue as well but they also didn’t how to replicate the scenario that caused the location update to stop. So, it is really hard to fix a problem that I do not know how to replicate it.

          If you know the exact steps to trigger that, please share to all of us.

    • Azhar B says:

      @JJMIAS, Were you able to accomplish this in ios 7.1 or later?

  3. Ricky, I don’t believe this will work over an extended run in the background. I just ran it for 2 hours and after the first hour things start to go bad. I believe the problem lies in the drainBGTaskList. Once the first task expires and it calls the expiration handler you will then call endBackgroundTask on every other task in your list which will leave you with no remaining background tasks running. I think a modification to drain all but the most current will work. I am going to modify and test but your thoughts would be appreciated.

    • Hi EC, Cool. Actually the BackgroundTaskManager is not programmed by me. I got it from somewhere else when I had trouble in handling the background tasks. When you have a new solution, may be you can share it on Github and let me know the link. I will test that out when I have time.

      • Ricky, My mods are here: https://github.com/ercollin/Location/tree/patch-1. It now keeps 1 and only 1 background task going with the option to stop them all such as when you leave background mode.

        • Hey EC, were you able to test this succesfully? I’m having a hard time keeping the app in the background for extended periods of time as well.

          I once had it running for 12 hours, but as soon as I started using the camera, games or other apps, the application got suspended.

          • Jan, what I posted yesterday was still not working as well as I’d hoped. I tested a modified version overnight last night and it worked perfectly though I did not test running other apps. It just sat there.

        • Thanks a lot, EC. I will do a testing this week, I will report back by the end of this week.

        • I just made some updates to my code at github. I have now tested it successfully for an extended duration along with running other apps.

  4. Thanks a lot, you saved my time. I have to update server about the location for every 10 min (both foreground and background) in both iOS 6 and iOS 7 . Does this method support extended period of time?

    • No problem. I am glad that it helps you. If you want to support iOS 6, I think you can get a list of methods from stackoverflow. But for iOS 7, this is the only method that I found that is working well. My original solution works well but with some glitch once in a while. I think EC has found a fix for the extended period. I personally haven’t test that yet. You may try his fix.

  5. It doesn’t work. It works for a certain time, but after an hour you are kicked off and the whole thing stops.

    I used the EC version and this is the trace. It starts promising

    2014-04-15 23:31:07.654 Location[359:60b] startLocationTracking
    2014-04-15 23:31:07.658 Location[359:60b] authorizationStatus authorized
    2014-04-15 23:31:07.687 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:08.396 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:09.397 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:10.390 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:11.372 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:12.384 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:13.388 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:14.388 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:15.376 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:16.365 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:17.365 Location[359:60b] locationManager didUpdateLocations
    2014-04-15 23:31:17.691 Location[359:60b] locationManager stop Updating after 10 seconds
    2014-04-15 23:31:31.380 Location[359:60b] locationManager didUpdateLocations
    2

    but it ends like this:

    2014-04-16 00:33:11.467 Location[359:60b] restartLocationUpdates
    2014-04-16 00:33:11.476 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:11.551 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:11.557 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:12.200 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:13.916 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:14.324 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:14.389 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:15.387 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:16.388 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:17.399 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:18.399 Location[359:60b] locationManager didUpdateLocations
    2014-04-16 00:33:18.525 Location[359:60b] ending background task with id -1
    2014-04-16 00:33:18.527 Location[359:60b] ending background task with id -2
    2014-04-16 00:33:18.530 Location[359:60b] ending background task with id -3
    2014-04-16 00:33:18.534 Location[359:60b] ending background task with id -4
    2014-04-16 00:33:18.537 Location[359:60b] ending background task with id -5
    2014-04-16 00:33:18.541 Location[359:60b] ending background task with id -6
    2014-04-16 00:33:18.545 Location[359:60b] ending background task with id -7
    2014-04-16 00:33:18.549 Location[359:60b] ending background task with id -8
    2014-04-16 00:33:18.551 Location[359:60b] ending background task with id -9
    2014-04-16 00:33:18.555 Location[359:60b] ending background task with id -10
    2014-04-16 00:33:18.557 Location[359:60b] ending background task with id -11
    2014-04-16 00:33:18.560 Location[359:60b] ending background task with id -12
    2014-04-16 00:33:18.563 Location[359:60b] ending background task with id -13
    2014-04-16 00:33:18.564 Location[359:60b] ending background task with id -14
    2014-04-16 00:33:18.566 Location[359:60b] ending background task with id -15
    2014-04-16 00:33:18.568 Location[359:60b] ending background task with id -16
    2014-04-16 00:33:18.570 Location[359:60b] ending background task with id -17
    2014-04-16 00:33:18.571 Location[359:60b] ending background task with id -18
    2014-04-16 00:33:18.573 Location[359:60b] ending background task with id -19
    2014-04-16 00:33:18.575 Location[359:60b] ending background task with id -20
    2014-04-16 00:33:18.576 Location[359:60b] ending background task with id -21
    2014-04-16 00:33:18.578 Location[359:60b] ending background task with id -22
    2014-04-16 00:33:18.579 Location[359:60b] ending background task with id -23
    2014-04-16 00:33:18.580 Location[359:60b] ending background task with id -24
    2014-04-16 00:33:18.582 Location[359:60b] ending background task with id -25
    2014-04-16 00:33:18.583 Location[359:60b] ending background task with id -26
    2014-04-16 00:33:18.585 Location[359:60b] ending background task with id -27
    2014-04-16 00:33:18.586 Location[359:60b] ending background task with id -28
    2014-04-16 00:33:18.588 Location[359:60b] ending background task with id -29
    2014-04-16 00:33:18.589 Location[359:60b] ending background task with id -30
    2014-04-16 00:33:18.591 Location[359:60b] ending background task with id -31
    2014-04-16 00:33:18.592 Location[359:60b] ending background task with id -32
    2014-04-16 00:33:18.594 Location[359:60b] ending background task with id -33
    2014-04-16 00:33:18.596 Location[359:60b] ending background task with id -34
    2014-04-16 00:33:18.598 Location[359:60b] ending background task with id -35
    2014-04-16 00:33:18.600 Location[359:60b] ending background task with id -36
    2014-04-16 00:33:18.602 Location[359:60b] ending background task with id -37
    2014-04-16 00:33:18.604 Location[359:60b] ending background task with id -38
    2014-04-16 00:33:18.606 Location[359:60b] ending background task with id -39
    2014-04-16 00:33:18.608 Location[359:60b] ending background task with id -40
    2014-04-16 00:33:18.610 Location[359:60b] ending background task with id -41
    2014-04-16 00:33:18.611 Location[359:60b] ending background task with id -42
    2014-04-16 00:33:18.613 Location[359:60b] ending background task with id -43
    2014-04-16 00:33:18.615 Location[359:60b] ending background task with id -44
    2014-04-16 00:33:18.617 Location[359:60b] ending background task with id -45
    2014-04-16 00:33:18.618 Location[359:60b] ending background task with id -46
    2014-04-16 00:33:18.620 Location[359:60b] ending background task with id -47
    2014-04-16 00:33:18.622 Location[359:60b] ending background task with id -48
    2014-04-16 00:33:18.624 Location[359:60b] ending background task with id -49
    2014-04-16 00:33:18.625 Location[359:60b] ending background task with id -50
    2014-04-16 00:33:18.628 Location[359:60b] ending background task with id -51
    2014-04-16 00:33:18.630 Location[359:60b] ending background task with id -52
    2014-04-16 00:33:18.631 Location[359:60b] ending background task with id -53
    2014-04-16 00:33:18.633 Location[359:60b] ending background task with id -54
    2014-04-16 00:33:18.635 Location[359:60b] ending background task with id -55
    2014-04-16 00:33:18.638 Location[359:60b] ending background task with id -56
    2014-04-16 00:33:18.640 Location[359:60b] ending background task with id -57
    2014-04-16 00:33:18.643 Location[359:60b] ending background task with id -58
    2014-04-16 00:33:18.646 Location[359:60b] ending background task with id -59
    2014-04-16 00:33:18.647 Location[359:60b] ending background task with id -60
    2014-04-16 00:33:18.650 Location[359:60b] ending background task with id -61
    2014-04-16 00:33:18.652 Location[359:60b] ending background task with id -62
    2014-04-16 00:33:18.656 Location[359:60b] ending background task with id -63
    2014-04-16 00:33:18.659 Location[359:60b] ending background task with id -64

    • Neil,
      After an hour, your server can not receive the location? What is the issue on the log your posted?

      I found a small bug on EC’s version. It should be _masterTaskId in stead of masterTaskId in the init function.

      -(id)init{
      self = [super init];
      if(self){
      _bgTaskIdList = [NSMutableArray array];
      _masterTaskId = UIBackgroundTaskInvalid;
      }
      return self;
      }

      Yesterday I have tested EC’s version. It was running for 3 hours (in the background) and the server received the location every minute. Today I am trying to run for 5 hours in the background and I will see if it is good.

  6. Francesco says:

    Hi mates, what about change location interval? I need to make the polling request interval greater than one minute, i.e 10min/30min/1hr, and i tough it could be simply reached changing the seconds related to the share model timer but it does not seems to work. It seems that it’s impossible to use intervals greater than 3mins. Any Ideas?

    • Hi Francesco, Do you mean change the self.shareModel.timer to restart the locationManager?

      I read from somewhere that the maximum background time in iOS 7 is 3 minutes, for iOS 6 and below is 10 minutes. So, I believe the maximum time for the timer to restart the locationManager is 3 minutes. I have’t test that out myself as the app that I have developed required me to send the location to the server every minute. May be you can share with us your results and findings here.

      • Francesco says:

        What i need is to get user location at time fixed intervals, even greater than 3mins. How would you have done if you needed to send the user location to a server every 5mins?

        • I see. I misunderstood your previous statement. To send the location to a server for every N minute, you just need to implement a new method (eg: updateLocationToServer) inside LocationTracker. Inside the method, choose the best location based on Accuracy and other criteria from self.shareModel.myLocationArray and send to server when this method is called. Remember to empty this array after a successful transaction, so that the old locations will be removed before the next N minute.

          To implement the N minute interval, just use a timer on App Delegate or whatever class to call [self.locationTracker updateLocationToServer];

          I think I will add a sample function to update the location to server when I am free.

          • Francesco says:

            Sorry man, it seems that we are not able to understand each other because i was not clear in the previous statement. What i really need is to get the location every N seconds, where N can be greater than 180secs (3mins). How can you reach this?

          • No problem. I will post the solution for you within these few days when I am free.

          • Francesco, I have added the sample code for sending the location to the server for N seconds. You may check out the latest solution from Github.

  7. I tested it on iphone 4 running on iOS 7. It crashes when goes in background.

    • So far, I have tested on iPhone 4s and above, they are running well. I haven’t test on iPhone 4 yet. Are you able to provide any crash log or troubleshoot the root cause for the crash?

  8. Hello,

    Excuse me, I followed the second part of the tutorial of Ray: http://www.raywenderlich.com/29948/backgrounding-for-ios ray
    related to Background Location Update and it works very well on iOS7 and 7.1.

    Kindly, could you explain to me which problem this article solves?

    Best regards

    • Really? Have you tested running the app for over 1 hour in the background and your server still receive the location from your mobile? Most of the solutions that are available before iOS 7 will get the app killed in the background when it was running for over 30 mins. I read that page and I saw a comment posted by Adamhoward1 on August 28, 2013 mentioned that it is not working on iOS 7.

  9. Hi RICKY,
    I needed to restart the locationManager after 5 minutes rather than after 1 minute, but the app is killed after 3 minutes in background.
    Can you please help me to resolve that ?
    Regards

    • Hi Nassim, The reason you want to to restart the locationManager every 5 minutes is to save battery? From my research, the maximum background time in iOS 7 is 3 minutes, for iOS 6 and below is 10 minutes. So, for iOS 7, the maximum time you can restart is about 2 minutes and 50 seconds. So, at this moment, I do not have any better solution for that.

  10. Hi Ricky,

    We compiled your github example (the updated EC one) and ran it on an iPhone 5S, 5, 4 and 4S. All running iOS 7.1 (iPhone 5S running iOS 7.11).
    It started running great and the iPhone 5 and 5S work well – however the 4 and 4S stopped and got suspended and didn’t restart the background task after about 3 hours…

    What do you think could be causing this ?

    Also did you try the code on iOS 6.1 ?

    Cheers, John

    • Hi John, I am using iPhone 4S (iOS 7.1). There was one time, I have tried to run it for 5 hours continuously on the background without much trouble. I am going to run a few more times to double confirm it. Can you run a few more times and report back?

      I have tried the code only on iOS 7.0 and above as the app that I am developing only supports iOS 7.0 and above. I think for iOS 6 +, you might need a different solution.

  11. Hi guys, does this solution works when you lock your device?

    The solution works OK on background for me, but when i lock the device it runs for 3 minutes and then nothing (the background task seems to be not refreshing properly)

    Does anyone come across some similar behaviour?

  12. Hi.
    Yesterday we was talked for background app continue working.
    still i got same issue with your demo . after 20 – 25 min its can not work. when device going to sleep mode / hibernate mode.
    Please help me to do continue running app .

    • my testing scenario is:
      open the app.
      put app to background
      lock the device for 20 to 25 min
      after 20 – 25 min app still going to suspend mode (i need to app in running mode )

      • Hi Ravi, I do know that sometimes there is an inconsistency issue. Sometimes, I can run for over 10 hours without a problem (connect with cable while charging), but sometimes the app can be suspended after > 1 hour. May I know what device that you are using? And what is the iOS version? I would need to collect more data and find a better solution.

  13. Brad Nelson says:

    Ricky, everything works great in background in ios 7.1. But still eats battery pretty good. How would u implement the significant change in location instead of just time?

    • Yes, batter problem is one of the things that I haven’t solve it yet. It consumes about 8-10% per hour. If the app consumes more than that, it is actually due to background App Refresh by other apps such as Facebook. If you switch off Background App Refresh for all other apps, I believe you will see 8-10% per hour. For my app, I have to get the location every minute. So, that is the solution that I need. Your app might be different from mine.

  14. Jeraldo says:

    I have come accross this kind of situation, I have an interval of 30 seconds (for testing) to update location and send the location the our server. It works for 5 minutes in the background and suddenly stops working. What could’ve probably cause it to stop?

    • Is it happen every single time or intermittently? I do know the inconsistency of app when the system decided to move the app from the background mode to the suspended mode (especially when the battery is low (< 50%)). I have tried to run the app for over 10 hours in the background with my phones plugged on my chargers, they do not have problem sending the location to the server every minute. I haven't found a solution to solve that yet.

      • Jeraldo says:

        Thanks Ricky. I have made it to work for an interval of 15 minutes. But for a few hours it just stops working. I have 2 timers, one for the 15 minute interval and another under 3 minutes for waking the application up.

        • Have you tested the app by plugging it on the charger? And also make the 3 minutes timer to be 2 minutes and 45 seconds (Just to give a room of buffer).

      • Jeraldo says:

        Also, what should be the recommended method to “wake up” the app in the background?

        • What do you mean by waking up the app in the background? You mean you want to do something when the app is in the background? Actually the current solution force to app to remain always active in the background. So, you can do a lot of things in the background. But sometimes, iOS decides to terminate the app in the background.

  15. Why do you call startLocationTracking on didFinishLaunching? May be this method calling in applicationDidEnterBackground, if you want work in background?

    • The uploaded code is just a sample to show you the way to get the location update continuously in iOS 7 including when the app is in background. You may instantiate the LocationTracker object anywhere you want and anywhere you need.

  16. Firas KADHUM says:

    Hi,

    Thank you so much for your solution, but I have few question to ask:
    1- The app with the sample you made, sends a location to server every one minutes, what if I want every 5 minutes? should I just send the interval time, or I must not use a value larger than 3 minutes (time that an app can stay in the back ground before it get suspended)?
    2- I want to keep sending location in both mode foreground and background, if I run the code in the same way as you did (startLocation Tracking in didfinish launching) will it still work regardless the the state of the app?

    3- can I start stop the location tracking whenever I want? (use may be button)

    Thank you so much

    • No problem.

      1. The time interval that you send the location to the server can be anything. The timeInterval to restart the locationMaanger (
      Check self.shareModel.timer in locationManager: didUpdateLocations in LocationTracker.m should be less than 3 minutes.
      2. Yes, the code is working fine for both foreground and background.
      3. Yes, you may do that. The app that I developed use button to start and stop location tracking as well.

  17. Renish Dadhaniya says:

    i know that this questions may be repeated some times but i need some clarifications so i asked here.

    My requirement is I got location using my iPhone every 20 sec and update my Web Application using the web services.It’s also working on Background.

    I know that i will got the location in background using the Background Fetch but i little confuse here.I want to update My web database every 20 sec using web services. is it possible to update Web database every 20 second using web service in Application Background mode?

    If available any demo then pls suggest me.

    Thanks in advance.

    • For your purpose, you might want to change timeInterval under didFinishLaunchingWithOptions to 20 seconds. Example:-

      NSTimeInterval time = 20.0;
      self.locationUpdateTimer =
      [NSTimer scheduledTimerWithTimeInterval:time
      target:self
      selector:@selector(updateLocation)
      userInfo:nil
      repeats:YES];

      For your purpose, you might also want to reduce the timeInterval for self.shareModel.timer under – locationManager: didUpdateLocations in LocationTracker.m to 20 seconds. And may be change the NSTime * delay10Seconds t0 5 seconds.

      You have to run a lot of testings in order to know if those parameters are good for your purpose.

  18. Is the BackgroundTaskManager will be approve by apple store?

    • Yes, it will. I have 2 live app on the app store right now using the same solution that I share in this article. You may check out my portfolio to find the app: http://mobileoop.com/my-portfolio Most like you can’t download Circle Watch as you are not from Malaysia. You may download Watch Over Me to play with it.

  19. sudhakar reddy says:

    Hi,
    Your tutorial is very helpful to me. Thank u so much.

  20. Durga Prasad says:

    Hi Ricky,
    My requirement was to run the application in the background for at-least a week.
    I have tested( iPhone 5S with iOS version 7.1) your code, sometimes it runs in the background for 4-5 days, sometimes only for a one day.
    I have gone through EC’s code as well, but I found yours and EC’s code almost the same!.
    Is it possible to track location in the background for such a long time(a week)

    • Yes, there is still consistency issue for running the location update on the background. I couldn’t pinpoint exactly where the problem is. I believe it is related to the background tasks.

      EC’s code is a copy of my original code with a fix on background tasks. So, they are almost identical. I have integrated EC’s fix on the background tasks on the main project on Github with additional functions. So, you should use the main project.

      Yes, it is possible. But, the solution that I share on the Github might not the best code for what you want to develop. As my code is only good for what I want to develop (Running location update for a short event up to 3 hours). So you should seek for other alternative if you want to get location update for a longer timeframe.

  21. EFDAL USTAOĞLU says:

    Hello Ricky,
    I found your code very helpful for my project, you saved a lot my time. Thank you very much. I’ve made some changes to your code for my project to do my job. For example I’m getting the period from my server , in what period i’m going to send the device’s location to server (5 min, 10 min, 30 min etc) and when I sent my location to server I’m getting the next period of time. In addition i’m adjusted the woken up time to 1 minute, so the app every 1 minute woken up get the current location and suspended. When the time comes to send the location to server it sends. Its working very well. However sometimes the app stops working. I couldn’t find the reason of it. In the office i’m sending the location and log them, everything working fine. I tried 3g and wireless as well. But at afternoon when i’m going home , i open the app on the background and it stops at some point and do not send the location updates on the background. Even though the location (0,0) where it is located in the middle of the sea 🙂 My guess is at some point the app couldn’t get the location and after that it stops working. I’m asking how can i handle no – internet contingency ? I’ve read your answers to others and you mentioned there is still inconsistency. Or the problem is because of it. Thank you

    • Sorry for late reply. I have been busy. No problem. I am glad that it helps you. Yes, the problem that you are facing is the inconsistency issue that most of us are facing as well. I hope that someone is able to figure out this and fix it for us. I have been busy with other projects and I do not have too much time in testing the location consistency lately.

  22. how can i get location update when application is close(not in background)

    • It is not possible with the solution that I share on Github. I heard that it is possible to do that in iOS 7.1 and above but until now I still haven’t find any good solution that points me in the right direction for doing that. I hope someone who knows will share it with all of us.

  23. Hi,

    Thanks for the tutorial, helped me a lot figure out how to implement background location in iOS 7!

    Did you take a look at WWDC 2014 sessions videos, about the new stuff coming in iOS 8 for Core Location ?
    Apparently it will be possible to do background location even when the app is closed.
    Any thoughts on that?

    More info: http://devstreaming.apple.com/videos/wwdc/2014/706xxjytntg51wd/706/706_whats_new_in_core_location.pdf?dl=1

    • I have watched all the location service related videos for WWDC 2014. May I know which video and at which minute it mentions about getting the location even when the app is closed?

  24. Jimmy Lee says:

    Hi Ricky, Thanks for your contribute. Let me clarify something. I think the reason of the inconsistency is that the phone will goes to deepsleep which suspend all the apps and if you have interval push of any kind (email, or push notification from other app, phone will wake up and your background task will start working again). Im developing an daemon app which always running foreground and interval x min to send location update if radius is bigger than x meter from previous location, but having problem because phone went to deepsleep.

    • Hi Jimmy, No problem. Yes, I believe the deepsleep is the main reason that suspends the app. But, the restart of the locationManager actually prevents the OS from entering into the deepsleep. From some testings, I found out that when the iPhones is fully charged, the locationManager can be restarted without much problem. When the battery is low (<50%), something prevents the restart of the locationManager. Thus, the OS enters the deepsleep which suspends the app.

  25. Hey Ricky!

    Thanks for your work! I’m currently trying to implement the same thing, but I can target only 7.1. I’m wondering, if all the workarounds are necessary in 7.1. Are you planning to update your post for 7.1? I also tried to understand your source code (I’m new to the whole iOS stuff), more comments would be helpful 😉

    • Actually the solution that I provided on Github works well on iOS 7.1. Some people mentioned that we can even get the location update on iOS 7.1 even when the app is killed or suspended, I couldn’t find any reliable solution on that yet. If I am able to find one, I will update the solution on Github.

  26. Hey guys, I am having a holiday in Bali, Indonesia. I am going to answer all the questions in a week time when I get back to Malaysia. See ya.

    • Thanks Ricky for such a great contribution, which saves me good effort.
      However, the inconsistence did bother me a bit. Sometimes, the APP is able to run more than 12 hours, sometimes, it get killed few hours. I observed when my APP got killed, the system reminded me that “background task 0 expired” couple of times before dies out, I wonder whether this is the root cause of this inconsistence we talked here.

      • Yes, the problem is related to the background task. I also believe the the battery level is a factor as well. When I have time, I will investigate further to understand better on the inconsistency and hope that I can come out with a better solution.

        • Hi! thanks for this code, it is being really usefull. Is this bug solved? if so, what was the problem?

          again, thanks

  27. Hii I am using your code and its very nicely done….but its not running forever i added this in my app and it runs for 6 hours then suddenly it shows
    2014/08/06 09:26:30:047 ending background task with id -656
    2014/08/06 09:26:30:047 kept background task id 657
    2014/08/06 09:26:30:047 kept master background task id 2
    2014/08/06 09:26:30:109 location is :2.97444
    2014/08/06 09:26:30:111 background remaining 61.959797
    2014/08/06 09:26:30:116 location is :2.97254
    2014/08/06 09:26:30:118 background remaining 61.952561
    2014/08/06 09:26:31:050 locationManager stop Updating after 10 seconds
    2014/08/06 09:27:28:034 background task 0 expired
    2014/08/06 09:27:28:034 background task 0 expired

    and my app kills in background…..Please provide a solution. !!
    Thanks

  28. Hello, great Job thank you very much.
    I don’t need constant location updates, I need some motion detection like walking/running/automotive and in some cases start GPS.
    I there a way to use your code with my needs?

  29. Can anyone help me with this?

    I get this when I am calling restartLocationUpdates

    *** -[LocationTracker respondsToSelector:]: message sent to deallocated instance 0x14577ca0

  30. Hi,
    I am working on location service and trying to run in background for lat, long from device. I have used CoreLocation framework for location service. Its all working when app is in background.
    It goes stop when delete app instance and it start become when start application again.
    I have tried on all version like iOS6, iOS7 and iOS8 bita etc.
    Please help me or

    • If I understand you correctly, you mean the location update stops when the app is deleted? Of course, you will need to have an active app in order to get the location update. The solution that I provided is to keep the app always active even when it is in the background. If the app is deleted or is killed, it will not work!

  31. Hi,
    first go all, you did an awesome job with this example and it makes my code work easier!

    But i have a problem, i can’t stop the background task on foreground, i’m trying to start the task ONLY in background and only if i had set ‘yes’ a switch… can you share an example like that?? (running on background if you turned on the switch at main screen)

    thank you for your time!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    • When I have time, I will do it together with the inconsistent issue when running in the background. It is going to take a while because I am busy with a freelance project. No problem.

  32. Hi RICKY, I appreciate your fantastic job.However, there is an improvement to this method. For example,In the case where watching a movie, there is no need to get the GPS information.
    So, I’d suggest a “Significant-Change Location Service” and “Region Monitoring”.
    Usually to get the GPS information by a timer. On the other hand, In case there is no need to get the GPS information, and use them.

    • Yes, using Significant-Change Location Service is better if your app does not need constant location update.

      As for the app that I developed, the users have the control on when to start getting the location update (eg: when they are running an event) and when to stop the location update (when they reach the destination). So, my app does not really get the location all the time. But when an event is running, the location will have to be sending to the server every N minute.

  33. Thanks for your quick reply.
    I will test this method by using this weekend.

  34. sagar patil says:

    Hi thanks for this tutorial. Its been very helpful. But i am having one problem in stopping the background task. I tried [self.locationTracker stopLocationTracking] and also draining all the background tasks but it wont stop.

    • I am not sure what is wrong with your code. This is what I believe, you declare and initialize a few different instances of locationTracker. One of them might be inside a different thread. So, you could not kill that instance from the main thread.

      The rule of thumb is to use the locationTracker as a singleton, so that you will always have only one instance of locationTracker.

  35. Hi, great job here thanks a lot for the contribution! I’m fairly new to iOS development so bear with me. Everything looks like it should work fine, but when I test it, the only output i get is: “updateLocation” which means it is executing the code in the AppDelegate but NOT executing anything in the locationTracker class. Is this an iOS 8 thing or am I missing something super obvious?

    Thanks in advance!

    • Hi Sean, No problem. Thanks for letting me know. I just updated the code for the support for iOS 8. A new key NSLocationAlwaysUsageDescription has been added on the PList which is a requirement to get location update in iOS 8. And before getting the location, requestAlwaysAuthorization will have to be called on iOS 8. Example:

      if(IS_OS_8_OR_LATER) {
      [locationManager requestAlwaysAuthorization];
      }
      [locationManager startUpdatingLocation];

      You may download the latest solution from Github and it should work well now.

      • Dear RICKY,
        Is iOS8 will also auto end app after 3 minutes, if the app do nothing in background ? or more time ?
        I know that end app after 10 minutes in iOS6 and 3 minutes in iOS7,
        How long in iOS8? Is any change?
        Because restartUpdatingLocation within 3 minutes is very consume battery ! But we no choose without restart within 3 minutes.
        Thanks.

        • I believe it is 3 minutes as well. I didn’t test it yet. I will have some free time this week and next week and I will test it out and report back.

        • I have tested the app on iOS 8, the background time is also 3 minutes. Thus, when you do not have the Background App Refresh enable for the app and your app is running in the background, you will receive the warning message: “background task 0 expired” after 3 minutes.

  36. Thank you for this great code example! Very useful.
    With your project example it works fine but when I create a new blank project, import your code files, I have a background task 0 expired after 3 min.
    I set Location update and background fetch for the background capabilities, do I miss additional setting in my project? can you help ?
    Thank you

    Regards

    Thierry

    • No problem. 😉 Hm… Actually I am unable to know what problem that you are having from your short description. It could be anything. Just do some more trials and errors, I believe you will figure it out.

      • Hello Ricky,
        Still not found the reason it expires after 3 min(IOS 7.1)
        I suspect some Apple-low-level restriction because if I create a blank project, import your code it works except if my bundle name is the same as the original one. So I have to change my organisation name or app name… Strange ?
        Tried also to suppress all Xcode data from my computer and also tried on another machine, same…
        BTW I have a compile error with BackgroundTaskManager.h: -(UIBackgroundTaskIdentifier) expected a type.
        I have to #import

        Regards

        Thierry

  37. Thinks Ricky,
    I do test after, it still end app within 3 minutes in iOS8.0.2

    • I have been doing trial and error on solving this issue the entire day today but I couldn’t solve it yet. But, I have found a good lead and I will do more testings these few days, I hope that I can come out with a good solution that will solve all the inconsistencies when running the location update in the background.

    • Initially, I thought the issue is related to the inconsistency of the solution that suspended the app when the app is running in the background. It is NOT!

      Anyone who finds that the location updates end at the 3rd minute should check the setting of the Background App Refresh of the device. Make sure that it is enable or else the location update in the background will end at the third minute!

      Step: Settings -> General ->Background App Refresh

      I have added the UIAlertView warning on the solution of the Github if the Background App Refresh is disable.

      PS: In addition to that, I might have found a way to solve the inconsistency issue that some of us have faced in the last few months. I will have to test more before update the solution.

  38. Hi Ricky. Your location update interval = 60 sec. What about 300 sec and more? What is the time limit in the background?

    • You mean the self.locationUpdateTimer on App Delegate? It is the timer to send to the location to the server. You may choose any time you want. Time limit for background task is 3 minutes. I use another timer to restart that. It is self.shareModel.timer on LocationTracker.m. It is 1 minutes as well. You can change this timer but the value must be less than 3 minutes.