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.

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:-
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.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
for(int i=0;i
{
continue;
}
//Select only valid location and also location with good accuracy
if(newLocation!=nil&& theAccuracy>0
&& theAccuracy<2000
&&(!(theLocation.latitude==0.0 && theLocation.longitude==0.0))){
self.myLastLocation = theLocation;
self.myLastLocationAccuracy= theAccuracy;
NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
[dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:@”latitude”];
[dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:@”longitude”];
[dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:@”theAccuracy”];
//Add the vallid location with good accuracy into an array
//Every 1 minute, I will select the best location based on accuracy and send to server
[self.shareModel.myLocationArray addObject:dict];
}
}
//If the timer still valid, return it (Will not run the code below)
if (self.shareModel.timer) {
return;
}
self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
[self.shareModel.bgTask beginNewBackgroundTask];
//Restart the locationMaanger after 1 minute
self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:60 target: self
selector: @selector(restartLocationUpdates)
userInfo: nil
repeats:NO];
//Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
//The location manager will only operate for 10 seconds to save battery
NSTimer * delay10Seconds;
delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:10 target: self
selector: @selector(stopLocationDelayBy10Seconds)
userInfo: nil
repeats: NO];
}
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.
Great article & source code.
I’ve looked through the entire of your source code, and fully understood your Location Tracker & Location ShareModel classes.
But I wonder what is the responsibility of Back ground Task Manager 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. Background TaskManager 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. Background TaskManager 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: 29469c4 18f2d8a327 63489d05329e ab8bb7f760f
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: 0x000 000008 badf00d
High lighted Thread: 2
Application Specific Information:
Ultrack GTS[32288] has active assertions beyond permitted time:
{(
identifier: Called by Ultrack GTS, from -[Background Task Manager begin New Background Task] process: Ultrack GTS[32288] permitted Background Duration: 180.000000 reason: finish Task owner pid:32288 preventSuspend prevent IdleSleep prevent SuspendOnSleep ,
identifier: Called by Ultrack GTS, from -[Background TaskManager begin New Background Task] process: Ultrack GTS[32288] permitted Background Duration: 180.000000 reason: finishTask owner pid:32288 prevent Suspend preventIdle Sleep allowIdle SleepOverride Enabled prevent SuspendOnSleep )}
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 -[Background TaskManager begin New BackgroundTask] process: MarketingClient [75619] permitted Background Duration: 40.000000 reason: finish TaskAfter Background ContentFetching owner pid:75619 preventSuspend preventIdleSleep prevent SuspendOnSleep
“
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.
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.
@JJMIAS, Were you able to accomplish this in ios 7.1 or later?
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 Background TaskManager 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: Mod. 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.
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.
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.
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.
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.
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.
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?
Hello,
Excuse me, I followed the second part of the tutorial of Ray: 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.
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.
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.
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?
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.
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.
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.
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).
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.
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.
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.
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 scheduledTimer WithTimeInterval: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.
Is the Background TaskManager 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. Most like you can’t download Circle Watch as you are not from Malaysia. You may download Watch Over Me to play with it.
Hi,
Your tutorial is very helpful to me. Thank u so much.
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.
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.
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.
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: WWDC2014
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?
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.
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.
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
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
Check your Background App Refresh!
No man background app refresh is on. Can u provide a solution for background location service. to update location just when user walks in background. please provide solution for that.
Do you solve that problem?
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?
Can anyone help me with this?
I get this when I am calling restartLocationUpdates
*** -[LocationTracker respondsToSelector:]: message sent to deallocated instance 0x14577ca0
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!
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.
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.
Thanks for your quick reply.
I will test this method by using this weekend.
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.
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.
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 Background TaskManager.h: -(UIBackground Task Identifier) expected a type.
I have to #import
Regards
Thierry
Check your Background App Refresh!
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.
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.
Hi.
I use Background Location Update Programming for iOS 7, it works fine. Thank you RICKY, but now i need to get location after killing the app.
I know that it is possible to get location after killing the app. LIfe360 sends user location, when the app is killed. Does anybody know how it is done.
If it is the user who killed the app, I believe there is no way to get the location from the device.
If it is the iOS which suspended the app by moving from background mode to suspended mode. There is a way to do that. I have figured that out but I need some time to test out the solution before uploading that to Git Hub.
I did research on Life360 some time ago. It is not possible to replicate exactly like what it does. It has its own technology and it collaborates very closely with the Telco by getting the location from the specific gadgets by using the cell towers instead of getting the location from the device itself. So, the app does not use too much battery because most of the process is done on the server end. I watched one video that showed some companies offer Life360 millions of dollar for the technology but they rejected the offer. So, I believe small players like us are not able to replicate exactly like that Life360 does.
When going to the background, timer delay10Seconds not work.
Timer delay10Seconds working correct only after “restartLocationUpdates”
Mike, you are right! I didn’t notice about that until you told me. I updated the latest solution on Github that will fix this issue. It is due to multithreading. The delay10Seconds was a local instance previously. When the app movse to background, the delay10Seconds timer that has been declared on the main thread will not be able to executed in the background thread. But, after the “restartLocationUpdates”, another delay10Seconds instance was declared and initialised on the background thread, so, it was able to run.
To avoid this problem again, I have moved delay10Seconds timer to the share Model which is the share instance in any of the threads.
Thank you very much!
Hello Ricky,
First of all thank you so much for providing such a great solution of running the application in background.
I am using your solution for running the application in background. It was running fine in iOS 7. But then I faced problem in iOS 8.
Then I checked this page again and applied the solution for iOS 8 suggested by you. Run the application in my iPhone with Xcode and it worked fine. but if I disconnect the iPhone from the Xcode then application is not running in the background 🙁
I run your demo app in my iPhone and it is working fine in both cases. iPhone connected with Xcode and
iPhone disconnected with Xcode
Then I cross checked my code with yours. And everything is same. So do you have any idea/suggestion why my application is not running in background while my iPhone is not connected with Xcode. Also please let me know if you nay more details.
Looking forward to hear from you soon. Thanks in advance!!
What is your iPhone’s iOS version?
I think you need to check your PList. For iOS 8, you will have add additional key (NSLocationAlwaysUsageDescription) on the PList to get extra permission from the user for getting the location (both foreground and background) from the device.
Hello Ricky,
My device’s iOS version is 8.0 (12A365). I already have added that key in my plist.
Here are some details of my plist file which may be helpful:
-> NSLocationAlwaysUsageDescription = Your location is needed for this app.
-> Application does not run in background = NO
-> Required background modes =
App plays audio or streams audio/video using AirPlay,
App registers for location updates,
App downloads content from the network
Are you able to upload your sample project to somewhere and send the link through my contact: contact me? May be it is faster for me to check for you.
Really very sorry for late reply.
Update : Your solution is working fine. it was an issue in my code. After solving it I am able to run my application in background.
Hello again,
I was testing my app running in the background for bigger time. And it did not work. Let me explain you in details.
I am working on one app which has one module of alarm. I set two alarms. the first alarm is supposed to fire after 6 hours, and the another one is supposed to fire after 10 hours. The first alarm (i..e after 6 hours) is fired as it should be but the second one is not fired. So do you have any idea why it not fired.
Any helps/ suggestions /ideas would be greatly appreciated.
Thanks 🙂
Hello Ricky ,
Firstly i want to thank you very much for your great code . Second i want to ask if i can update location in background state in specific distance not time .
Thanks a lot 🙂
Yes, I think you may use distanceFilter + desiredAccuracy for the locationManager. The function didUpdateLocations will only trigger after the device is moving for a certain distance. If you do not keep a timer to keep the locationManager always active in the background, there is a high chance the iOS will move your app from Background mode to Suspended mode when the device is idle.
After the app is suspended and when the device has started to move again, you will receive a locationKey from didFinishLaunchingWithOptions, there is where you will know how to handle the new location update by creating a new locationManager.
When I have free time to test on the location update after the iOS suspends the app, I will update the new solution on Github.
Hi Ricky,
Why is the master task needed in the background task manager? Is there a reason why the master task can’t be drained? After all, the most recent background task will always be retained, so why is the master needed as well?
Thanks.
Just a thought, maybe it is causing the app suspended in the background because of memory leaks? Did you ever test it for this kind of situation?
Yes, it is possible. I will do some more testings when I have time.
Hello,
Great tutorial and the explanantion also. i ran your code on iOS 8.1 and it stopped working after 20 min or so. Can u help me. The only change i did was to change the restart time from 1 min to 2 min.
If it is not the inconsistent issue that some of us are facing once in a while, then you might be doing something wrong. Sorry, I don’t have time to help you. You have to do the experiment yourself.
Any progress on the inconsistency issue? I have been following this thread with great interest in the hopes of hearing of one. I actually don’t need the location info as such, but am using the locationManager to drive my app to run other processes on a regular basis in the background, and have run into the same inconsistency issue (which is a killer for my purposes). If you know of any other way to insure regular execution of a background task, I would greatly welcome the advice. Otherwise, I eagerly await a solution for the inconsistency problem.
As of now, there is no progress yet. I don’t have time to test it. Event if I have time, I don’t know how to test it as it only happens once in a while and there is no pattern on how it actually occurs.
Ugh. Know the feeling (both about lack of time and inconsistent bugs!).
While I have you, I have now come upon another problem that perhaps you can help with: I can get timed background updating to work well in the simulator, but when I run on the iPhone itself it suspends execution when the app moves to the background (e.g.,, I hit the home button), then resumes when I reactivate the app. I’m testing on an iPhone 5 running iOS 8.1. I’ve confirmed that Background App Refresh is enabled (both in settings, and by a status call in the app. I can also get background location updates using more standard methods, but it crumps after awhile, which is why I turned to your method. Any thoughts would be most appreciated!
Please ignore my last question. Problem resolved (if not fully solved). I had a premature endBackgroundTask. Once repositioned, it now runs in the background fine. Of course, not sure why it worked in the simulator at all, but I won’t argue with success.
Hi Ricky,
You code work great for me, but only in debug mode and it doesn’t then device shut off from xcode. Is there a reason why it’s happens?
And thank you for great job.
I don’t understand what you mean that it only works on “debug mode”.
AdHoc version doesn’t work
I still don’t understand what you meant by “doesn’t work”? What do you see on debug but do not see on AdHoc? Please explain in details and please don’t waste my time.
Sorry I’m an idiot everything works fine.
What about deferedLocationUpdates? Although defered Location Updates somehow has failed in my end, I wonder if you could use it successfully.
What I face is the constant kCLErrorDeferredFailed, inspite of didUpdateLocation being called properly. I have tried to learn about it but have found little success. I hope you can shed some light to it
I believe defered Location Updates can only be used with [self. shareModel .location Manager start Monitoring start Monitoring Significant Location Changes]; instead of start Updating Location.
You should do some trials and errors in order to understand it better.
I have one solution that I want to share related to getting the location from the device even when the apps is killed/ terminated (not in the background). I believe that solution can be used with defered Location Updates. I am still trying to find time to complete that tutorial and update the solution to Git Hub.
I tried defered updates in Ipad Simulator, with location simulated between freeway and custom location. In both cases the result was kCLErrorDeferredFailed, which according to Apple docs refer to GPS problem, i.e. hardware malfunction. Yet the didUpdateLocation callback is still called, which surprises me since the call back means that the hardware is working probably
Also, I have another query. Why Back ground Task Manager is being used? I tested your code in my Ipad Simulator without Back ground Task, and it worked for more than an hour. I simulated iPad locked state, ran other applications , in console it kept on giving me the updated location. So what added advantage is UI Back ground Task is providing?
I never try that in simulator as I think it is not good enough to test this kind of thing. We need Back ground Task Manager when the app is in the background. eg: When you put the main app in the background, lock the screen or run other apps. Back ground Task Manager is needed to keep the app alive in the background. Without Back ground Task Manager, most likely you app will be terminated or unable to get location after 3 minutes in the background.
Hello there Mate,
Thanks for sharing.
I have one query: is this method already used in an app which has been accepted by the reviewers of Apple?
Yes, please see the apps on my portfolio. both the apps are using the same solution that I uploaded on Git Hub. You can download Watch Over Me for testing.
Hi Rick,
Thanks for excellent solution. I had 1 particular problem on ios7 if I keep my app running for long time more than 7 hrs. Around 7 hrs or so app doesn’t get any location update and its logoff from my services. Have you encountered something similar and have some suggestion how I can solve this?
Thanks
Swapnil
Yes, that is part of the inconsistent issue that some of us have experienced once in a while. If you are using other apps like Waze or Google Map, I believe battery will not last that long as well. So, I believe iOS has designed to kill off any background running apps when the battery reaches a certain %.
I have tried once with my iPhone running an app with this background location update solution for more than 12 hours, it can send the location update to the server every single minute. This is because I plug in charger and the battery is always at 90-100% level. So, I guess battery level influent the decision of iOS to kill any apps running in background.
Hi Rick,
I recently tested your code in Ipad 3,4 (IOS 8.0.2). While connected to my iMac, it worked perfectly for 5 hrs nonstop, but when I tested it independently, it worked for 3 hrs . See, each time the location Manager is being restarted, I fire a UILocal Notification. In both cases, I ran my Ipad with only 45% battery, and kept other apps open as well.
Can you tell me why the UILocal Notification worked for 3 hrs on independent testing?
I don’t think your battery level will stay the same level if you plug the iPad on your iMac. Your app will run at the same time the battery will be charged.
I have mentioned earlier that I did a testing and run the app for over 12 hours, it can update the location to the server continuously every single minute.
The inconsistency issue is only happened when the device is not charging and it uses the power from the battery. So, I believe battery level has some kind of influence for iOS to decide if it wants to keep or kill the app or not in the background.
And why BackgroundFetch Mode is opened in the Capabilities section. Location Updates in background mode should be enough , I think; We are not implementing any fetch completion in App Delegate, then why Background fetch is to be selected?
You may make a test run. Remove the code that forces the user to enable the Background Fetch. Test run the app in the background for over 3 minutes, then you will see the warning message: “background task 0 expired” after 3 minutes. Then, your app will either crash or you can not get the location update anymore.
So, Background App Refresh should be enable in order for the app to get location continuously from the background.
Thanks for this awesome tutorial. I am using this on my app and it is working really well.
However, there is one situation I have to handle, which is to allow the app to update location and send it to the server even if the app is not on foreground or background, but has been terminated by the user or the system to free memory to other apps.
I saw in one of your comments that you came up with a solution for this but didn’t have time to put it on a tutorial. Would you mind to share how did you accomplish this?
Thanks!
Denis
No problem. Yes, I found the solution. I have tested it for a few weeks and I can get the location even when the app is terminated/killed.
I would need some time to write the tutorial and share the solution on Github and StackOverFlow. My freelance project is at the final phrase now, I should have some free time within the next 2 weeks to complete the tutorial on Auto Layout and also the tutorial on getting location even the app is killed/terminated..
Thanks Ricky,
Mind to at least share the idea behind your solution?
I am thinking about using the Significant Change Location service since I think it is the only one that wakes up the app if it is terminated. So I was thinking about maybe doing a mix of this service with your solution on this blog. I hope that works.
Hi Denis, I just completed the tutorial. Please take a look at: location update for iOS 7-8 even in killed / terminated mode
Hi Ricky,
Thanks for the great tutorial you provide.. i tried it and it works perfectly.
Im still a newbie on iOs development, I use Swift language when coding. So when I try to migrate ur code on my Swift project.. I get this error on
-(UI Background TaskIdentifier) beginNew BackgroundTask; ‘Expected Type’ on Background TaskManager.h
Please help with this problem.
Thanks in advance 🙂
Thanks Ricky for a nice tutorial.
Everything is fine, but when i try to fetch the speed i always get -1m/s.
-(void)location Manager: (CLLocationManager *) manager didUpdate Locations:(NSArray *) locations {
self. newLocation = [locations lastObject];
double dcSpeed = [newLocation speed];
}
Here dcSpeed always return me negative value, please help me to solve the issue.
Thanks in advance
Hi Ricky,
Just wondered if you had finished the tutorial on getting location even the app is killed/terminated.
Thanks in advance
The tutorial is completed, please take at look at: location update for iOS 7-8 even in killed / terminated mode
The long wait is OVER.. haha 😀
thanks for this very helpful tutorial.. 😀 Happy New Year…!
No problem. 😉 One developer mentioned that the solution does not work well on iOS 8. I only have iPod Touch with iOS 8. If you have iPhone with iOS 8, are you able to help me test if the solution works well on iOS 8?
Happy New Year to you too. 😉
Hi Ricky,
Thanks for the tutorial, it is very helpful.
There is one more question in my app, My app using socket to update the location with backend server, is there anyway to keep socket alive when user locked the screen?
One more thing I concern about is if I can launch the app to the AppStore if I using the VoIP background model in my scenario, because there is no “Voice” over IP 🙁
Hi Ricky,
Thanks you for great post. We implemented your code in our project and could be able to track device location when silent push received. But after some time when receiving silent push (we put alert text, so we could see if silent push received) ios didreceiveremotenotification fetchcompletionhandler was not called, thus app was not able to get and send back device location. What we found was that if device is PLUGGED in that it will work 100%, if not that it will not work.
Any idea?
I cant background location in ios8.x .
I already add the required information for iOS 8
Any thoughts here on Deferred Location and its implementation? I have been working with it for a few weeks in developing an app that tries to determine the length of time the phone has been inactive by the user. So far I have been able to get it to consistently space time intervals apart easily for the deferred location, but it doesn’t actually stop the constant updating of the location as well, which I understand to be a bug.
So far, I haven’t use the deferred location API because the apps that I developed need the consistent location update at a specific time interval.
Hi Ricky,
Thanks for the tutorial,i have implemented your code in one of my project and able to get location updates in background ,but “background task 0 expired” is getting in console after some time,but the app is not crashing and under device settings -> Diagnostics & Usage -> crash reports are generating as has active assertions beyond permitted time, i think they are related to background execution but not able to trace when they are generating ,
and how to end the background task if user keeps the app in background forever
can you please help me solve above issue
Thanks in advance
Make sure that the background app refresh is On.
Hi Ricky thank you for this code and awesome tut. I have some questions that would really help me.
1) I am trying to stop the location updates when a user clicks a button. I simply made a button and call StopLocationTracking. After stopping it still sends information to the server about the lastLocation also it STILL updates the location sometimes. How can i fix this? This is how the console showed:
stopLocationTracking
2015-01-28 12:15:38.962 Location [9433:60b] location Manager stop Updating after 10 seconds
2015-01-28 12:16:28.910 Location [9433:60b] update Location
2015-01-28 12:16:28.912 Location [9433:60b] update LocationToServer
2015-01-28 12:16:28.914 Location [9433:60b] My Best location:{
latitude = “57.65236”;
longitude = “11.91026”;
theAccuracy = 65;
}
2015-01-28 12:16:28.916 Location [9433:60b] Send to Server: Latitude (57.652363) Longitude (11.910262) Accuracy (65.000000)
2015-01-28 12:17:28.910 Location [9433:60b] update Location
2015-01-28 12:17:28.912 Location [9433:60b] update LocationToServer
2015-01-28 12:17:28.914 Location [9433:60b] My Best location:{
}
2015-01-28 12:17:28.915 Location [9433:60b] Unable to get location, use the last known location
2015-01-28 12:17:28.917 Location [9433:60b] Send to Server: Latitude (57.652363) Longitude (11.910262) Accuracy (65.000000)
2015-01-28 12:18:28.910 Location [9433:60b] update Location
2015-01-28 12:18:28.912 Location [9433:60b] update LocationToServer
2015-01-28 12:18:28.914 Location [9433:60b] My Best location:{
}
2015-01-28 12:18:28.915 Location [9433:60b] Unable to get location, use the last known location
2015-01-28 12:18:28.917 Location [9433:60b] Send to Server: Latitude (57.652363) Longitude (11.910262) Accuracy(65.000000)
2015-01-28 12:18:43.417 Location [9433:60b] started background task 2
2015-01-28 12:18:43.429 Location [9433:60b] kept background task id 2
2015-01-28 12:18:43.442 Location [9433:60b] kept master background task id 1
2015-01-28 12:18:43.458 Location [9433:60b] started background task 3
2015-01-28 12:18:43.468 Location [9433:60b] ending background task with id -2
2015-01-28 12:18:43.472 Location [9433:60b] kept background task id 3
2015-01-28 12:18:43.477 Location [9433:60b] kept master background task id 1
2015-01-28 12:18:43.542 Location [9433:60b] location Manager didUpdate Locations
2015-01-28 12:18:43.637 Location [9433:60b] started background task 4
2015-01-28 12:18:43.638 Location [9433:60b] ending background task with id -3
2015-01-28 12:18:43.640 Location [9433:60b] kept background task id 4
2015-01-28 12:18:43.641 Location [9433:60b] kept master background task id 1
2015-01-28 12:18:43.642 Location [9433:60b] location Manager didUpdate Locations
The code that I uploaded on Github might not be complete because the main purpose of the code is to simulate the case for getting the location continuously when the app is in the Background.
If you want to stop the Location Manager completely, here are some additional snippet of the codes that might help.
On Location AppDelegate.m
-(void) stopLocation Update {
[self. location Tracker stopLocation Tracking];
if(self. location UpdateTimer){
[self. location UpdateTimer invalidate];
self. location UpdateTimer = nil;
}
}
LocationTracker.m
– (void) stop Location Tracking {
NSLog (@”stopLocation Tracking”);
if (self. shareModel.timer) {
[self .shareModel.timer invalidate];
self .shareModel.timer = nil;
}
CLLocation Manager *location Manager = [Location Tracker shared Location Manager];
[location Manager stop Updating Location];
[self. shareModel. bgTask endAll Background Tasks];
if (self. shareModel. delay10Seconds) {
[self. shareModel .delay10Seconds invalidate];
self. shareModel. delay10Seconds = nil;
}
}
You may give the above code a try.
FYI, I haven’t test the code yet. I will find some time to test the code and update the solution on Github.
Thank you!
I will try to tweak your code a little. My original thought is that the user will have a “switch on/off” button that will decide when he wants to send the data to the server. When its off then it would shutdown all location services including when it is in the background. For this i am thinking of using a shared boolean instance variable. I think i can put it on top of the code on both methods that you provided there and it would work. I will try and come back!
Thank you again!
Now that i go through the code i don not even need the boolean…
Ok so i tried the code that you provided. After i clicked the stop button it stopped all location updates(everything) when the app was in the foreground. But after i went to background again it started: Here is the code after i pressed on the stop button:
2015-01-29 12:43:04.922 PickMeUp [10209:60b] in stop
2015-01-29 12:43:04.923 PickMeUp [10209:60b] stopLocation Tracking
2015-01-29 12:43:04.924 PickMeUp [10209:60b] ending background task with id -6
2015-01-29 12:43:04.926 PickMeUp [10209:60b] no more background tasks running
2015-01-29 12:44:08.458 PickMeUp [10209:60b] started master task 7
2015-01-29 12:44:08.573 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:44:08.616 PickMeUp [10209:60b] started background task 8
2015-01-29 12:44:08.620 PickMeUp [10209:60b] kept background task id 8
2015-01-29 12:44:08.621 PickMeUp [10209:60b] kept master background task id 7
2015-01-29 12:44:08.622 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:44:08.804 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:44:09.229 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:44:14.092 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:44:18.624 PickMeUp [10209:60b] location Manager stop Updating after 10 seconds
2015-01-29 12:45:08.623 PickMeUp [10209:60b] restart LocationUpdates
2015-01-29 12:45:08.670 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:45:08.674 PickMeUp [10209:60b] started background task 9
2015-01-29 12:45:08.675 PickMeUp [10209:60b] ending background task with id -8
2015-01-29 12:45:08.679 PickMeUp [10209:60b] kept background task id 9
2015-01-29 12:45:08.680 PickMeUp [10209:60b] kept master background task id 7
2015-01-29 12:45:08.685 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:45:08.961 PickMeUp [10209:60b] location Manager didUpdate Locations
2015-01-29 12:45:09.411 PickMeUp [10209:60b] location Manager didUpdate Locations
You would need another BOOL property on shareModel to determine if the LocationTracker needs to create a new LocationManager and run the backgroundTask when the app is going to the background or otherwise.
It is something like:-
-(void)application Enter Background{
if(self. shareModel. doIReallyNeed ToRun TheLocation Manager){
CLLocation Manager *locationManager = [LocationTracker sharedLocation Manager];
location Manager. delegate = self;
location Manager. desiredAccuracy = kCLLocation Accuracy Best ForNavigation;
location Manager. distanceFilter = kCLDistance FilterNone;
if (IS_OS_8_OR_LATER) {
[location Manager request Always Authorization];
}
[location Manager startUpdating Location];
//Use the Background TaskManager to manage all the background Task
self. shareModel .bgTask = [Background TaskManager shared Background Task Manager];
[self. shareModel .bgTask beginNew Background Task];
}
}
You should figure out the rest on your own.
Hi TIMOCIN,
You found a solution yet?
Can you share me your solution. Thank you so much.
Hi Ricky,
Thank you for sharing the codes with us, I appreciate it.
I don’t know if you have already test it on iOS 8, from what I tested, it doesn’t work on iOS 8 ( it only works when you connect your device to Xcode and run app from Xcode, when doing that means you never stop your app running in the background).
Rgds
I have been using the same solution on iOS 8 almost on a daily basis. It works extremely well on iOS 8. You must have done something wrong on your end.
In order to prove that you are wrong, I take another step forward. I am running an app that is using the same solution that I am uploaded to Github. The app will send the coordinates to the server every 1 minute.
I started to run the app on iPod Touch Gen 5 with iOS 8.1.2 at time: 19:17 pm. Then, I tapped the home button to make the app running in the background. Lastly, I tapped on the Top Right Hand corner of the device (Sleep Button) to turn off the screen and lock the device. Nope. It does not connect to XCode, computer or any other electricity plug. And, I purposely put it far away from my computer table.
Here are the screen shots from the server end:-

Current Time: 20:38 PM. It has been running extremely well for over 1 hour and counting! Surprise?
I would be appreciate if you spend more time in testing before coming here to make a comment about “the solution doe not work”.
Sorry Ricky, if what I post irritated you and also I didn’t add some explanations. Again if what I post irritate or hurt you, that’s not what I want and I apologize in advance. I saw lots of you post about location stuff and I’m sure you got good knowledge about iOS GPS locations, that’s why I want to share my opinion about this, maybe we can find better solution by talking to each other.
1. Believe me I want this work or make it work as same as you and most of others do.
2. I have read all the codes, and I fully understand what you did. And I read through the comments I know you got a problem sometime it stops in the background.
3. When I say it doesn’t work I didn’t mean it fully not working at all. Actually I know most of time it works, it we don’t change the timer.
Now let’s talk about the problem. Why sometime it stops, why I can’t change restart Location Updates timer to 5 mins instead of 1 min?
To understand this, we just need to clear two things (I’m sorry I didn’t put too much for this, but I’m sure you will understand this):
1. Background task: 3 mins at most in background if you call begin Background TaskWith Expiration Handler.
2. Background mode (in this case we talk about background location): location update event will refresh background Time Remaining.
So we review the problems again:
1. why sometime it stops: So if after stopLocation DelayBy10Seconds called 3 mins no location update event, app will stop. start from iPhone 5, if locationManager DidPause LocationUpdates get called it will also stop unexpectedly.
2. why I can’t change restart LocationUpdates timer to 5 mins instead of 1 min: same thing after stopLocation DelayBy 10Seconds called, the app get 3 mins to running in the background mode, it need location update event (in this app: restart LocationUpdates) to refresh background TimeRemaining.
(This is what I got after change timer 1 min to 5 mins:
Feb 2 14:36:44 tonys-iPhone Location[4267] : background task 0 expired
Feb 2 14:36:44 tonys-iPhone Location[4267] : background task 0 expired
Feb 2 14:36:49 tonys-iPhone assertiond[58] : has active assertions beyond permitted time:
{(
id: 4267-36B8324A- 2990-4627 -845A- 4DE849ACD869 name: Called by Location, from -[Background TaskManager begin New BackgroundTask] process: permitted Background Duration: 180.000000 reason: finishTask owner pid:4267 preventSuspend preventIdleSleep preventSuspendOnSleep ,
id: 4267-30832B45- AF1A-4E99- 8C50- 0890508117E8 name: Called by Location, from -[Background TaskManager begin New Background Task] process: permitted Background Duration: 180.000000 reason: finishTask owner pid:4267 preventSuspend preventIdleSleep prevent SuspendOnSleep
)}
Feb 2 14:36:49 tonys-iPhone assertiond[58] : Forcing crash report of …
)
At end, why I say this doesn’t work as I expected?
First, GPS need time to connect to satellite (this cost lot battery as well).
Second, 30 secs wouldn’t be enough for getting a good GPS location.
Rgds
Hi Tony,
No problem. 😉 We definitely have some miscommunications. You can not set the timer to 5 mins because the maximum background time allowed for iOS 7 is 3 minutes. For iOS 6 and below, it was 10 minutes.
Before the 3 minutes background time expires, you will have to restart the location service. If you wait until after 3 minutes, the background time has expired, then the iOS will suspend all the background services for the app. During the suspended mode, You will not be able to do anything from the background anymore (unless you have the region monitoring or start Monitoring Significant Location Changes implemented, that would be another topic on its own.)
So, the maximum time for you to restart the location service is 2 minutes and 59 seconds. To play safe, I would set it at 2 minutes and 30 seconds.
Hey Ricky!
Thank you very much for this great job!
I have successfully adopted your code in my test project.
But I have a problem. When I kill the app – location services icon is still active.
– I switch off location services.
– Location services usage icon persists forever (many hours – over 10 hours without any app running on the phone);
– Location services usage icon hides instantly when I delete my test project OR go to Privacy->Location Services and switch Location Services off for my app.
Can you help me to solve this? Any thoughts?
Thanks in advance!
I mean:
“I switch off location services IN MY CODE AT APP TERMINATION”.
Hi Nick,
If you are using [location Manager start Updating Location], when you kill the app, the location service icon should not be there anymore. But if you are using [location Manager start Monitoring Significant Location Changes], the location service icon will still be there even after you kill the app because “start Monitoring Significant Location Changes” will work even after you kill the app.
By any chance, your project contains “start Monitoring Significant Location Changes”?
You may refer to this article: update location in killed mode for more information
Thank you Rick!
Yes, you’re correct. My code contains “start Monitoring Significant Location Changes”.
I need a way to somehow stop this method’s activity.
Could you please give me a clue.
Thanks in advance!
Nick
The problem that I would like to switch locations services usage off even using start Monitoring Significant Location Changes:
Hi Nick,
Unfortunately, I believe there is no way to swift the location service icon off if you want to use start Monitoring Significant Location Changes.
Rick,
My problem is when I use SignificantLocationChanges: there is no callback called by iOS in background that provides me with updated location.
Is there a workaround to do this?
What do you mean by there is no “callback”? You didn’t receive anything from didFinish Launching WithOptions with the key “UIApplication LaunchOptions LocationKey” after the device has been moving more than 500 meters from the last know location?
You should check out this article. There is a complete GitHub project as well for you to play with it.
Thanks! We tried your code.
We also tested the code on device.
Device was on the table (not changing its’ position) all night long with locked screen.
The app was running, but was not foreground before screen was locked.
After 2-3 hours of running in the way I described – app stopped any activity with the server.
Then in the morning. I’ve unlocked the screen – the app did not start sending location.
Then I’ve put the app into foreground – the app started location updates.
Hi Nick,
You may try to do another experiment by using the same setup but the device plugged to a power source. Then, you may report back the result.
From my own experiment, when a device is plugged to a power source and the battery remained 90-100% level, the app will not be suspended. But, when battery level dropped to a certain %, the iOS will decide to suspend some running apps that are consuming a lot of battery. There is a big chance that your app will be suspended.
I don’t know what are the exact criteria that Apple used to suspend the app. I don’t have too much time to do R&D with the location service solution.
But there is one solution that you may try:
– A. 1 location Manager instance (MonitoringSignificantLocationChanges)
– B. 1 location Manager instance (update location for every N minute)
For whatever reason when iOS suspended the app, the location Manager B will also be killed in the background. But when there is a significant location changes, you may use the delegate method of the location manager A to recreate the instance for location manger B and then starting update the location again.
I have thought about this solution for quite a while but I am still not free to do R&D on that.
Hi Ricky,
First off, Thank you so much for this post!! It was very helpful to in understanding background location updates. I have just started working with iOS and I have a question that might seem a bit silly.
I was going through the code you had posted on Github and am not able to entirely understand the part where you call “begin New Background Task”. From what i have read about background tasks, you need to call a dispatch async to make something happen in the background task. As such, I dont understand how the timer you have set is running in the background since you have not called a dispatch async.
I have been trying to figure out what is happening for quite some time and can not find any helpful information online. Thank you in advance!
Hi, I’m wondering in which way is this better than apples way where you just set the background mode for location updates and ther getting delivered location updates in forground and background. Please I realy need to know, I’m using theirs code, but if thist is better in any way for user then I’ll pick this one.
Hi Ricky,
Thanks, We have used this code.
But, we can’t use cellular data for internet, so can’t able to test that sample app while traveling. We did not see the app in the cellular data enabling page of settings. Is there any option to have this on device settings?
We have tested app in iPhone 6 + and iPhone 5s with the version of iOS 8.1.2
Hi Ricky,
This sample app give the location where we don’t have internet ?
If so, how we can receive the location
Without the internet, we simply unable to get the location and also send the location to the server.
Our current internet is using the Server/Client model. But in the future when the Mesh networking has matured. Yes, it is possible to get the location without internet connection.
Until then, just assume that the location based app is useless when the device does not have internet connection.
Hi Ricky,
first off all I would say: Nice work! 🙂
I have a question concerning the n-minute tracking. I modified your code that the timer is restarted two times before tracking location and send it to the server. But this is only works if I connect the iPhone 5 with my Mac. If it is not connected every 3 minutes the location is tracked and send to the server. Even though the duration is about 6 minutes.
I tested it on version 8.1.3.
greetz
SebSpi
How about use the original code and do a testing and let me know your result?
Hi,
i want to update the location every 10 minutes. So i have to restart the timer without tracking the location right? But after testing some different cases I think that you have to restart the Location Manager every 3 minute? Is this right?
greetz
SebSpi
Yes, if you want to keep the location manager active in the background, you will have to restart the location manager every 3 minutes or less because the maximum background time for iOS 7 and above is 3 minutes. If you delay the time by more than 3 minutes, the iOS will suspend the app and you can not do anything in the background already.
Ok thank you Ricky for your help. A last short question.
What do you think what accuracy is needed to get a respectable location?
No problem. 😉
The setting for accuracy is really depends on the need of your app. If your app needs real time navigation, then use kCLLocation AccuracyBest ForNavigation. If your app does not need to be too accurate, you may use kCLLocation AccuracyKilometer
or kCLLocation AccuracyBest. Using lesser accuracy will help to save some battery.
You will need to do some experiments for your app to understand which one is the best for the purpose of your app. You may read the apple documentation for more info: Location Manager Accuracy
Maximum background time is minimum 10 minutes but with IOS 9 I’ve measured > 20 minutes. What is the source of your information for 3 minutes?
Hi Ricky-
Thanks for all this work! I have an app that needs to behave more or less like a fitness app in that it needs to receive very frequent location updates so that a walking/running path can be traced with high accuracy. Prior to iOS 8, everything was working fine when the app is in the foreground, with or without the screen locked (I did not let it run in the background before).
But now in iOS 8.1, when I lock the screen, the app continues to work, generally, but it does not receive location updates in real-time. It caches location updates and sends them all at once when the screen is unlocked. This is unacceptable behavior since the app needs to react to location updates immediately.
I updated the app by turning on background location and now the app quits/terminates/crashes very consistently ~50 seconds after I lock the screen.
This issue doesn’t seem to be exactly what your solution tackles, but perhaps it is. Do you think your solution will help? Have you encountered anything like this before?
Thanks for your thoughts.
Hi Ricky,
first off all I would say: Nice work! 🙂
I have a question concerning the n-minute tracking. I modified your code and the timer is restarted 7 times before tracking location and send it to the server. But this work only when i connect the iPhone 5 with my Mac. If it is not connected every 7 minutes the location is tracked and send to the server. Even it working in ios 7 and ios 8,but in ios 8.1.3 its working but stops completely after 30 minutes & its not running in back ground.The location update is not getting to server and one thing if i run the project in debugging mode then its working perfectly and when i disconnected the device its not working and stops after 30 minutes,help me out from this
Iam not able to access the application in ios 8.1.3,so help me to take out from this.
Thanks
Vinod Jha
Guys (and Ricky of course),
I’ve read this post and Ricky’s latest post on getting updates while app is suspended/killed in detail. I can confirm after extensive testing that both solutions work great on iOS 8.1 etc etc. However, I am having some trouble combining them and wonder if anyone has had success in doing something similar.
Basically, I am trying to create a proof of concept whereby I get highly accurate user location updates as often as possible *regardless of app state*. Ricky’s code from this post (“Location” project in GitHub) succeeds very well at preventing the OS from ever moving the app from background to suspended. I’ve gotten continuous (like 1 per second), highly accurate location updates for something like 12 hours using this method after I put the app into the background.
Ricky’s other solution, in the post at succeeds in having the app woken up from suspended/ terminated state by a significant location change.
The problem is: When my app is terminated by the user or the OS, and then woken up by a significant location change (i.e. didFinishLaunching is called with UI ApplicationLaunch Options LocationKey), then executing Ricky’s solution from this post seems NOT to work, and indeed the app only has 3 minutes of execution time before it is killed.
My goal is to restart the continuous location updates as soon as the app is woken up by a significant location change, and have those updates continue indefinitely, as I observed happens when the location is merely backgrounded after it is run (but not woken up from suspended).
Any help would be greatly appreciated, happy to share what I know.
Hi RICKY,
Thank you so much, your solution is very helpful to me. I run your example OK.
But i wanna ask you 1 question, when I add your LocationTracker in my ViewController.
I put: self.locationTracker = [[PeriodicManager alloc] init]; in viewDidLoad.
Now, i want to begin tracking when user touch button, so in IBAction touched event, i call:
[self.locationTracker startLocationTracking];
self.locationUpdateTimer = [NSTimer bla bla…];
But when i test with my device, it only run with 3 minutes. (if i call startLocationTracking in viewDidLoad, it run normally).
Can you help me to fix it. Thank you so much, (sorry for my English)
It work normally when i connect my device to Xcode.
When i unplug cable, app work only in 3 minutes.
Did you find any solution. I have the same problem. Works fine when the cable is connect with xcode7 but the application does not run in background when i start it from device
My device: iphone 5C (8.3 – 66% battery) and 5S (8.1.2 – 100%).
I Am spending 5 days trying some plugin after search got your program it is working fantastic and give example start and stop button using html5,cordova configure action ….enable background task ..
is it possibe give ur project cordova plugin?
ur project working perfect but i am copying your into myproject for on off based send the data to server…lattitude and longitude not getting
Hi Ricky,
I have been playing around with your code from github and am I wondering why background tasks are repeatedly created and ended. From my experimenting with the code on iOS 8.3, with my device plugged in to my laptop, only the call to create a background task in LocationTracker :: application EnterBackground is needed. This first call creates “the master background task”, which is then killed by the OS after 3 minutes. If I comment out the other call to create new background tasks, I still get location updates and the location is uploaded to the server ever minute. I haven’t tested with the device not plugged in, so maybe they are needed then, but it would nice to get a better understanding.
The code seems to do unnecessary things and needs a big refactor.
Hi Ricky
Thanks for a great solution! It’s work very well but it happens that the unit “drops” the GPS signal for a short while. then the app does not have a valid background task and BackgroundTimeRemaining starts and counts down from 3 minutes. after 3 minutes crashes the app with “has activewear assertions beyond Permitted Time” … do you have any idea how to restart the Location Manager to recover BackgroundTimeRemaining.
Thanks
Mattias
Just set the ‘location’ flag in your UIBackgroundModes. You can find it at your targets capabilities. This flag will tell the OS that the application requires to stay active in the background, thus it will not be suspended by the scheduler.
Hi Ricky ,
I am using the same code in my project but application crash at second time.
[self.bgTaskIdList addObject:@(bgTaskId)];
Thread 1: EXC_BAD_ACCESS(code=1, address=0x57534252)
Thanks,
Rahul
Hi
I have made an app on Android where I constantly get the location updates from the GPS every 2 second. Then I have other logic (where and speed dependent) on when to send the location to the server or not. I have never done an IOS app before and started with your example as a start but I would like to make it a little bit more simple with this continous update but it also have to happen in the background. Could you please guide of what to remove to make it as I stated?
Dear Ricky,
Thank you for sharing this article with us. It is a huge help i think for everybody. However i face one issue with it can’t get my head around.
We have integrated your solution to an app we’re working on. It works perfectly on every device i install it to from xcode, but when i send it to a test device via crashlytics, the background location fetching times out after 10-15 minutes. Do i need to set something up with the app id/provisioning profile?
Thank you for your answer in advance!
Regards,
Zoltan
Hi I have used this method. This works fine when I debug but when I create ipa file and install it on iphone it is not working.
For the person who reads this blog entry but doesn’t find that any of the tips are working around the web regarding background location and deferred updates:
I highly recommend you watch the Core Location video here: https://developer.apple.com/videos/wwdc/2013/ – look for the “What’s New in Core Location” video. It will teach you how to use deferred updates correctly and what the errors mean.
Really all the WWDC videos on the API are more informative than the API reference itself.
How can i stop the timers and background tasks for location update when i get a success result. and start another request when the functions are called again?
I tried the answer you provided for Timocin I Think its working thank you
Has anyone had any experience with getting this to work on iOS 9. So far my app keeps getting killed after running for a few minutes in the background.
Same here, app is getting killed after several minutes at iOS 9
The solution for iOS 9 is actually very simple because you can decide the background location updates for each location manager you have to set this property to the location manager you’re using. This way you can use different location managers with different purposes. Just add the following lines:
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@”9.0″)) {
[clController setAllowsBackgroundLocationUpdates:true];
}
The documentation states the following:
By default, this is NO for applications linked against iOS 9.0 or later, regardless of minimum deployment target.
With UIBackgroundModes set to include “location” in Info.plist, you must also set this property to YES at runtime whenever calling -startUpdatingLocation with the intent to continue in the background.
Setting this property to YES when UIBackgroundModes does not include “location” is a fatal error.
Resetting this property to NO is equivalent to omitting “location” from the UIBackgroundModes value. Access to location is still permitted whenever the application is running (ie not suspended), and has sufficient authorization (ie it has WhenInUse authorization and is in use, or it has Always authorization). However, the app will still be subject to the usual task suspension rules.
See -requestWhenInUseAuthorization and -requestAlwaysAuthorization for more details on possible authorization values.
I tried setting setAllowsBackgroundLocationUpdates, but that doesn’t fix the problem.
Same here. After 3minutes on iOS9 it stops. Anyone solved it?
build richy’s project with xcode6 is working;
lucky, i restore the xcode6 before update!
launchoption always nil in xcode 7 (IOS 9) so i can’t able to check the condition” if ([ launchOptions objectForKey: UIApplication LaunchOptions LocationKey])”
To make it work on ios 9 change the singleton initializer in LocationTracker.m to
+ (CLLocation Manager *) sharedLocation Manager {
static CLLocation Manager *_locationManager;
@synchronized(self) {
if (_locationManager == nil) {
_locationManager = [[ CLLocationManager alloc] init];
if( [_locationManager responds ToSelector: @selector(allows Background Location Updates)]){
[_locationManager setAllows Background LocationUpdates:YES];
}
_locationManager. desiredAccuracy = kCLLocatio nAccuracyBest ForNavigation;
}
}
return _locationManager;
}
THANK YOU SOOOOO MUCH!!!!!! I’ve been looking all over for the iOS9 solution for this and trying lots of things, and this finally got it to work 🙂 Thank you! You’re a wonderful human being.
I tried you solution for iOS 9 but after 4-5 hours the code in background will stop. Any solution?
The same thing is happening to me. I think it is iOS killing off the process in the background, so I’m currently going to implement the successive mobileoop post, and if that doesn’t work, then I will use incremental geofencing. I’ll report how it goes. Were you able to find a solution?
Hi
Did you find the solution for your problem? Even i’m facing the same issue. After 3 hours background location update stops completely.
Hi Ricky ,
After long search I got your source code thanks for that,My requirement is when my app is went suspended state i need to update my location to my server. For that we need to use Significant-Change Location Service.
So i have used Your source code and i have follow that. To get my location when app is suspended ,If we used Significant-Change Location Service we get location update after we travelled 500 meters in suspended state .i have tested ,It won’t work .So how can i get location when app is suspended state .
I have run my app in iOS 9 Version.
Below ways i have suspended my app and tested :-
1.I have run the app ,i have received the location in didupdate method on that place i have implemented local notification. if location updated i know about via local notification .
2.after that i have double tab the home button ,i kill my app .
3. next i have travelled nearly 2km .I did’t receive any local notification .
4.Significant-Change Location Service used means .we travelled 500 meters, location will update ,but i did’t receive anything.
5.local notification received only we can able to know suspended state it will work.But i did’t receive anything.
Please help out from this thanks in advance.
(Sorry for my english)
The class design seems convoluted and in-need of a re-factor. It is hard to tell what is going on. E.g. locationShareModel class has pointer properties that should be moved to locationTracker. I.e. *timer, *delay10Seconds, and * bgTask should be moved.
The code was developed more than 2 years ago. I didn’t actively maintain it because I didn’t develop any apps that needs background services in the last 1 year. If you are able to help to improve the code, please let me know or send in the pull request to the Github project. Thanks.
Too much code duplication.
Rename startLocationTracking to startLocationTrackingIfLocationServicesEnabledAndAuthorized
stop Location Tracking is never called anywhere in your sample
endAllBackgroundTasks is never called
Thank u a soo much Ricky 🙂 .Great work !!
For those who had the error uibackground task identifier expected a type in Background TaskManager.h .
You can simply add #import . That works for me 🙂
(sorry for bad english )
#import *
Hi Ricky,
Thanks for the tutorial . The app worked perfectly for IOS 9, but on IOS 8.4
the app is crashing with the below message.
Dec 29 15:42:11 iPhone Location[251] : started background task 3
Dec 29 15:42:11 iPhone Location[251] : ending background task with id -2
Dec 29 15:42:11 iPhone Location[251] : kept background task id 3
Dec 29 15:42:11 iPhone Location[251] : kept master background task id 1
Dec 29 15:42:11 iPhone Location[251] : -[__ NSCFDictionary application Enter Background]: unrecognized selector sent to instance 0x17577470
Dec 29 15:42:11 iPhone Location[251] : *** Terminating app due to uncaught exception ‘NS InvalidArgument Exception’, reason: ‘-[__ NSCFDictionary application Enter Background]: unrecognized selector sent to instance 0x17577470’
*** First throw call stack:
Device : iphone 5c
OS Version : 8.4
xcode version : 7.2
How to Reproduce the Crash :
1 . After launching the app, press the home button and open any other app.
2. lock and unlock the screen.
3. open and close few other apps.
4. Open your application and lock the screen again.
By following the above 4 steps couple of times the app got crashed.
Also got the below error, when crash happened
iPhone Location[288] : kept background task id 3
iPhone Location[288] : kept master background task id 1
iPhone diagnosticd[118] : error evaluating process info – pid: 288, punique: 288
iPhone diagnosticd[118] : error evaluating process info – pid: 288, punique: 288
Thanks and Regards
Harshith
Hi Ricky,
great Code, thank you for that. I used and modified the code a little for my purposes.
I am just wondering: When the application enters background, you start the location tracker and let it run
line 53: [locationManager start Updating Location];
Why don’t you use the restart LocationUpdates method (which resets the timer) and will stop the location updates after 10 seconds? You have the background tasks running that will reactivate the location anager after 1 minute anyway. So currently, when the app is in background mode, the locationManager is active all the time (and consumes battery).
Is this necessary to keep the app alive? In my tests it worked well with stopping the location updates and reactivating it every 5 minutes.
Thanks
Stephan
Hi, it is any project in Swift language for this?
But I am Unable to Get the Location Updates in Terminated State ?
have to Start the location Updates , Continue the Updates in while Driving and have to Stop the Location Updates when User Stopped Some where for 5 MInutes ?
– (void) locationManager: (CLLocationManager *)manager didUpdate Locations: (NSArray *)locations
{
NSLog(@”track point last lat long is here %@”,[data. lastObject value ForKey:@”time”] );
NSLog(@”latitude is here %@”, [data. lastObject valueForKey:@”latitude”]);
NSNumber *numberValue = [data. lastObject objectForKey: @”time”];
lasttrackpoint timeand dateis=[numberValue longLongValue];
lastrowid = [[DBManager getSharedInstance] getLastROWID];
newLocation= [locations lastObject];
latitude.text = [NSString stringWithFormat: @”%.8f”,newLocation. coordinate.latitude];
longitude.text = [NSString stringWithFormat: @”%.8f”,newLocation. coordinate.longitude];
altitude.text = [NSString stringWithFormat: @”%.0f m”,newLocation. altitude];
[speed setText: [NSString stringWithFormat: @”%lu”, (unsigned long) locations .count]];
BOOL success = NO;
NSDate *localDate = newLocation.timestamp;
NSLog (@”Timeinmilliseconds are here : %lli”, [@(floor ([newLocation. timestamp timeIntervalSince1970] * 1000)) longLongValue]);
long long value= [@(floor([newLocation .timestamp timeIntervalSince1970] * 1000)) longLongValue];
NSLog (@”database time is here %lld”, lasttrackpoint timeanddateis);
NSLog (@”value is here %lld”,value);
long long difference = value- lasttrackpoint timeanddateis;
float seconds = difference/1000;
NSLog(@”seconds are here %f”,seconds);
NSLog(@”difference is here %lld”, difference);
NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] seconds FromGMTForDate :localDate];
gmtDatestring = [localDate dateByAdding TimeInterval :timeZoneOffset];
NSLog(@”gmt date is here %@”,gmtDatestring);
long interval = [newLocation. timestamp timeIntervalSinceNow];
//if (fabs(interval)=0 && newLocation. horizontalAccuracy0 && ![[NSUserDefaults standardUserDefaults] boolForKey: @”locationStarted”]) {
if (seconds > 300.00000) {
success = [[DBManager getSharedInstance] updateTrack:value latitude: [[data.lastObject valueForKey:@”latitude”] doubleValue ] longitude: [[data.lastObject valueForKey:@”longitude”] doubleValue] rowids:lastrowid];
// [self generateimage];
[[NSUserDefaults standardUser Defaults] setBool: NO forKey:@”locationStarted”];
//[self. locationManager stopUpdatingLocation];
}
// else{
success= [[DBManager getSharedInstance] saveTrack:value latitude:newLocation .coordinate. latitude longitude: newLocation. coordinate. longitude];
success = [[DBManager getSharedInstance]
saveLocation: 1 latitude: newLocation.coordinate.latitude longitude:newLocation .coordinate.longitude time:value provider:@”YES” rowids:lastrowid];
// }
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@”locationStarted”];
}
else if([[NSUserDefaults standardUserDefaults] boolForKey: @”locationStarted”]) {
success = [[DBManager getSharedInstance]
saveLocation: 1 latitude: newLocation. coordinate.latitude longitude: newLocation .coordinate.longitude time:value provider:@”YES” rowids:lastrowid];
}
else {
// if (track tripendcordinate sarray.count==0 ) {
if (seconds > 300.00000) {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@”locationStarted”];
success = [[DBManager getSharedInstance] updateTrack:value latitude: newLocation. coordinate.latitude longitude: newLocation. coordinate.longitude rowids:lastrowid];
[self. locationManager stopUpdating Location];
}
}
NSLog(@”count is here %@”,[tracktripend cordinatesarray valueForKey:@”endlat”]);
}
Hi,
I m able to get locations in background at max. 6 hrs after that app get suspended. Can u tell me what is the issue.
Hi Ricky,
Thanks for the tutorial . The app works perfectly as expected only for first 2-3 hours, later it does not update the location. Any help would be appreciated.
Great Code, thank u a soo much Ricky.
Hi Ricky, thanks for sharing this…it’s been very helpful! One question though…can I expect this to work the same way using the requestWhenInUseAuthorization status? I tried it out but the app is getting suspended after a few minutes.
Thanks for the tutorial. I have implemented the code same way, and it is giving location updates after poll time defined. But the app is get killed in background after half or one hour. What would the reason? Plz help.
Hello, interesting topic. We are using it for our app. After 3 days of app running in the background there is a notification from iOS: ”Applications XX has been using your location in the background. Do you want to continue allowing this?” Any idea of how to avoid this?
Hey , i just tried this tutorial with my existing swift project and background task expires after 15-20 minutes , than i created other objective c test project and its work like a charm there … idk why this is happening .. is there any swift version for this tutorial.
Hey, I want the Same thing in swift, Is there any source for that. Thank you …
I Also Want to integrate it in Swift project Please Help me as soon as possible.
Thank You.
thank you nice tutorial
hi,
i tried code and it works fine. After killing the app, it wakes up in the background due to location update and keep running as long as it is getting location updates.
but it stops working as i turn off the location service. Is there any way to check that user has turned off the location service when app wakes up in the background due to location update?