How to run location updates in background continuously in ios - ios

UIApplication* app = [UIApplication sharedApplication];
_backgroundTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:_backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid;
}];
[self startTimer];
NSLog(#"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
-(void)startTimer
{
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:60.0
target:self
selector:#selector(repeatedMethod)
userInfo:nil
repeats:YES];
}
I'm able to run successfully when my app is in foreground but when I come to background if
backgroundTimeRemaining:10 it is running for 3 minutes but when backgroundTimeRemaining:176
it is running continuously. One thing I did not understand is why backgroundTimeRemaining is showing different numbers.How to run process continuously in Background. One thing I need to mention is my background process contains location updates. I'm very new to ios. Any help would be appreciable.

You need to set below key values in your app's info.plist file
Required background modes : App registers for location updates!
As shown in below image and implement you location manager delegate methods in AppDelegate so that its there even your app is in any view controller.
Setting the above key value in info.plist will tell ios to enable background mode for location services.

Read "Getting Location Events in the Background (iOS Only)" in:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW10
Basically your app needs to ask for permission to have a background mode for this, and use the location APIs rather than a time. You'll do some setup (get default location manager, set a delegate), call "startUpdatingLocation" from the CLLocationManager class, and then get periodic callbacks with new locations.
Keep in mind you'll drain the user's phone battery pretty fast if you do this, and Apple will reject your app from the App Store unless you give a disclaimer about this.

Set your CLLocationManager's pausesLocationUpdatesAutomatically to NO. It may help you.
For more info check Apple's Location manger documentation.

Related

Automatic ON/OFF the GPS tracking in an app running in Background

How can i stop and start the GPS tracking when an application running in background. i Can able to stop tracking in the application, but didn't got any way to start the application. I looking for answers for followings.
1.whether i can use push notification silently to start GPS tracking.
2.I tried with local notification, but it require user interaction to start the process. Is there any best ways to do this.
My problem: Initially i can able start tracking the user location and can stop that after some time in background. I wanted to start the tracking next day. Im looking for a way to start tracking in background.
Actually my application is basically the location tracking application. if the launches the application, the app starts tracking until the time 8:00 pm (stops automatically). Again started tracking next day 8:00 am.
If you started location updates while your app is running in background, these updates will not last longer than whatever time iOS granted for your background task (currently 180 sec).
Location updates must be started while the app is active, doing this ensures the updates keep coming even after your app goes to background, assuming you configured your app background modes properly - see Capabilities/Background Modes/Location updates in Xcode.
Even though, if your app is terminated, the delivery of new location events stops altogether.
If you want to temporary suppress standard location updates, please use
allowDeferredLocationUpdatesUntilTraveled:timeout:
When updates are deferred, GPS receiver is still powered, but no CPU activity happens, as the receiver will not trigger events. I did not test power consumption in this mode myself, but people mention ~2% battery drain per hour.
Have you tried this
-(void)applicationDidEnterBackground {
[self.locationManager stopUpdatingLocation];
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
target:self.locationManager
selector:#selector(startUpdatingLocation)
userInfo:nil
repeats:YES];
}
Set intervalBackground Update to 1 day

Long running background task in iOS

I know this is a very common question. I have read many answer but not found out the appropriate answer for me. That's why I post this question and hope someone will show me how to fix my code.
I have function startUpdate to update location using CLLocationManager. In applicationDidEnterBackground method, I write something like below:
[self startUpdate]; // position1
NSLog(#"applicationDidEnterBackground");
__block UIBackgroundTaskIdentifier bgTask;
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
[self startUpdate]; // position2
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self startUpdate]; // position3
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://google.com"]];
});
I tried to put [self startUpdate] at one of three positions (position1, 2, 3) and sometime it works, sometime not, and I do not know why.
In case it works, updating just run in 3 minutes event. If I call startUpdate when app is in foreground, then put app to background, updating will last 15 minutes with real device, and more than 1hour with simulator ( I don't know exactly, after 1 hour, i thought it would last forever then I stop testing). So what is different between: startupdate in foreground-> go to background vs startupdate in background; simulator vs real device?
right after position3, I called following line to open safari
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://google.com"]];
But it does not work. So what types of task can be executed here, in background?
I need to keep a service running forever. Some search results say that it's impossible. But some familiar apps did that (Facebook,... keeps service to receive notifications). How can they do that?
Thank you so much,
The exact behaviour of location services has been clarified in the latest update to the Core Location documentation. It now states -
The standard location service delivers events normally while an app is
running in the foreground. When your app is in the background, this
service delivers events only when the location-updates background mode
is enabled for the app. This service does not relaunch iOS apps that
have been terminated.
The significant location change service delivers events normally while
an app is running in the foreground or background. For a terminated
iOS app, this service relaunches the app to deliver events. Use of
this service requires “Always” authorization from the user.
So, it seems that for the best chance of continuing to receive location updates in the background you should switch to significant location change monitoring once you move to the background state and restore full location monitoring once you return to the foreground.

iOS7.1 LocationManager pausing when entering background (works in 7.0)

Slightly confused on this one so I broke it down to a test app.
Simple singleton handling locationManager. I have turned on location support in the background under capabilities. Map is also enabled.
The location manager is running all the time but as soon as I put the application in to the background, it pauses.
I have read many posts about people trying to start location manager in the background, but mine is already running. I assumed by enabling it under capabilities, it would continue to run in the background. As soon as the app resumes, so does location manager.
Do I need to start looking in to beginBackgroundTaskWithExpirationHandler?
UPDATE
The code works in 7.06 and not 7.1.1? what did they change?
I believe you must set your applications background modes to allow location updates. To do this edit your apps .plist file and add "location" as a "Required background mode" see the Apple docs for more background modes (here)
in appDelegete.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[locationmanger startUpdatingLocation];//start your location update method here
//then add this code
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundTask];
}];
}
-(void) endBackgroundTask
{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
}
it will work now

iOS 7 Background Modes - Not For App Store (No Rules Apply)

For the bounty, I am not interested in GPS or audio background modes as the former uses too much of the battery and the latter prevents any other audio from being used, otherwise facing audio interruption, thus ending background processes. I will need a way to be continuously processing in the background, so background modes that trigger occasionally are also out of the question.
If there is some way to run the application in the background, even by ignoring Apple's rules, I am interested in trying it. If the answer is VOIP, I am unsure where to begin the implementation, as all of my research has come up too high level or as a failure. How will my application be able to run in the background using the VOIP background mode. Without any added code, the application refuses to run in the background.
I know that with iOS 7, background modes have changed again. I would like to be able to run my application (that will never need to be approved on the iOS App Store) in the background. I would also like to be able to stop execution in the background until a specific time in the future.
For example, I would like it to run a process for 15 minutes, schedule the next task and then sleep until that time. For now, I've had to run a silent track in the background for background processing, but I would like to be able to have the application truly sleep during that time - also, playing real music or making a phone call are "handy features" of the iPhone and I don't like losing them.
I know there is also GPS, but that consumes an enormous amount of battery. The other background modes don't seem to give full control of background processing and timing to the application and leave a large portion of the timing and execution duration to the OS.
What I need is to be able to have my application process in the background for minutes at a time and then sleep until a fairly specific interval and continue processing. Is this possible with a better approach than I am currently using?
I've seen that VOIP used to be a possibility, but I'm not sure that it will work, as I don't need the application to run one simple task in the background, but rather to continue whatever was running in the foreground before the application was pushed to the background. Also, individual tasks could take upwards of 1 hour to complete, so they won't be able to transfer when the background task expires. All of my assumptions are based off this thread.
Edit: There seems to be a terrible drop off rate with this method. At random, the recursion will seemingly fail for seemingly no reason (maybe a system timeout on execution?). If I place the recursion before ending the background task, the OS kills my application, but if I put it after, it occasionally seems to stop the background tasks at some point. I have seen it stop in the middle of my "allotted background time", as well.
In short, the below method does seem to run indefinitely, but not infinitely. Is there either a way to make the runtime guaranteed to be infinite or another solution?
It seems that using VOIP was leagues easier than I had first thought.
All that is required to run my application indefinitely (unfortunately sleeping is not an option) is to add voip to the selected Background Modes, either in the plist or in Target's Capabilities. After that, adding and running this code once, in an object that is never deallocated (your AppDelegate works nicely here), will allow for infinite background processing time:
- (void)infiniteBackgroundLoop
{
__block UIApplication *applicationBlockReference = [UIApplication sharedApplication];
__block AppDelegate *appDelegateBlockReference = self;
__block UIBackgroundTaskIdentifier backgroundTask = [applicationBlockReference beginBackgroundTaskWithExpirationHandler:^
{
[applicationBlockReference endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
[appDelegateBlockReference infiniteBackgroundLoop];
}];
}
In order to allow sleeping indefinitely, add a break to the recursion.
I used background fetch to achieve something similar.
You can use this to keep your app active in the background.
I have the a demo, see if it helps you:
Add these properties to your .h file -
#property (nonatomic, strong) NSTimer *updateTimer;
#property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
Now suppose you have a action on button --> btnStartClicked then your method would be like :
-(IBAction)btnStartClicked:(UIButton *)sender {
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(calculateNextNumber)
userInfo:nil
repeats:YES];
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background handler called. Not running background tasks anymore.");
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}];
}
-(void)calculateNextNumber{
#autoreleasepool {
// this will be executed no matter app is in foreground or background
}
}
and if you need to stop it use this method,
- (IBAction)btnStopClicked:(UIButton *)sender {
[self.updateTimer invalidate];
self.updateTimer = nil;
if (self.backgroundTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
i = 0;
}
We also played with background modes in our app, and I check all solution that found, and can say that there is only one way to stay active in background and is not "VOIP", because "VOIP" gives your app wake-up every 5-6 minutes not infinity run.
In documentation about setKeepAliveTimeout:handler: you can see that this method will call handler block at minimum every 600 second, and block has a maximum of 10 seconds to perform any needed tasks and exit.
To clean this you can add NSLog(#"time remain: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]); to your infiniteBackgroundLoop implementation. Because second and next call beginBackgroundTaskWithExpirationHandler not get same time of background run as first call.
Another working way is Location Manager, yes is bad because use lot of battery but is get you that you want - app newer stop.
The implementation can be easily found there
You could use background fetch and set the regresh rate to a short NSTimeInterval.
In your didFinishLaunchingWithOptions: try to add:
[[UIApplication sharedApplication] setMinimumBackgroundFetch:1];
I haven't tested this, let me know if this could be a starting point.

How is it possible to ensure a constant continuous update of location when iOS app is in the background?

One requirement for our iOS app is to monitor location changes in the background. We have implemented "locationManager startMonitoringForRegion:region", unfortunately we realised when testing the app thoroughly that it is too little precise to fulfil our needs.
We then used "locationManager startUpdatingLocation" to increase accuracy of location. In the foreground everything worked out quite good, this location precision is pretty much what we want.
Now the problem is when the app is in the background, the event "didUpdateLocations" is not called on regular basis. We observed this by looking into log file. What happens is pretty much always the same, the first 15 minutes the app updates the location regularly and then suddenly abruptly stops. After about a 5 minute break it carries on with updating the location for again about 15 minutes. And this continues on in the same way.
We probably made the mistake in the implementation in background handling.
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
if(rootViewController._selectedLocation == nil)
{
NSLog(#"selected location is nil and app entered background");
[rootViewController.locationManager stopUpdatingLocation];
}
else
{
NSLog(#"selected location is not nil and app entered background");
[rootViewController.locationManager startUpdatingLocation];
}
[app endBackgroundTask:bgTask];
}];
This seem to be called about every 20 minutes and the location is updated again. What are we doing wrong and how can we get a regular location update without any interruptions? We tested this with iPhone 5 and also important to know it was stationary.
You should add to your application plist file the following value:
Required background modes
It is an array telling the system what you app need when in background. For the position at item 0, you should inform the value:
App registers for location updates
In case of doubt, you can see in this link what I'm talking about: iOS Multitasking: Background Location

Resources