I have an app that posts data to a server. This data is only posted if the user is within a certain distance to a location. I regisered for background location updates in hope that would allow me to keep the background going. But after about 17-18 minutes, the background stops executing.
I thought it might have been because of the locationManager.pauseslocationupdatesautomatically. But even when I set that to false, the app still terminates at around 17 minutes. Here is the code for my app delegate.
//
// BAAppDelegate.m
// Beacon App
//
// Created by Huy Ly on 2/10/13.
// Copyright (c) 2013 Placesign. All rights reserved.
//
#import "BAAppDelegate.h"
#implementation BAAppDelegate
#synthesize backgroundAnnouncementRevision, backgroundAnnouncementText, backgroundOfferDescription, backgroundOfferName, backgroundOfferPrice, backgroundOfferRevision, isAnnouncing, isOffering, locationManager, targetLocation, currentLocation, beaconTimer;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
NSLog(#"Application will resign active");
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"Application entered background");
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager setPausesLocationUpdatesAutomatically:YES];
[locationManager startUpdatingLocation];
NSLog(#"Starting timer for posting in background");
/*
//Runs the Timer on a background task main thread
UIApplication *app = [UIApplication sharedApplication];
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];*/
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
beaconTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(sendBeacon) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:beaconTimer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(#"Application entered foreground");
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
[beaconTimer invalidate];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"Application became active");
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
[beaconTimer invalidate];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
NSLog(#"Application will terminate");
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[beaconTimer invalidate];
}
-(void) sendBeacon{
NSLog(#"Beacon Background Send Started");
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if ([[NSUserDefaults standardUserDefaults]valueForKey:#"PlaceID"]== nil) {
isAnnouncing = FALSE;
isOffering = FALSE;
}
//Do a single distance check to see if user is still within bounds
//Get the current location
[locationManager startUpdatingLocation];
//Compare current location with target location
CLLocationDistance distance = [currentLocation distanceFromLocation:targetLocation];
distance=distance/1000;
//If user is within location boundary, posts to server
if (distance < 0.1 || true) {
NSLog(#"Background Sent");
//Set Up the NSURL
NSString *urlString = [standardUserDefaults valueForKey:#"statusUpdate"];
NSURL *url = [NSURL URLWithString:urlString];
NSString *jsonString = [[NSString alloc] initWithFormat:#"{\"Announcement\":{\"Text\":\"%#\",\"ElementContext\":{\"Revision\":%#,\"Source\":{\"ID\":0,\"Type\":0}}},\"Offer\":{\"Description\":\"%#\",\"ElementContext\":{\"Revision\":%#,\"Source\":{\"ID\":0,\"Type\":0}},\"Name\":\"%#\",\"Price\":%#},\"OpStatus\":{\"ElementContext\":{\"Revision\":0,\"Source\":{\"ID\":0,\"Type\":0}},\"Value\":0},\"PlaceID\":%#,\"ResourcesOnPremise\":[{\"ElementContext\":{\"Revision\":0,\"Source\":{\"ID\":%#,\"Type\":1}},\"OnPremiseStatus\":2,\"Resource\":{\"ID\":%#,\"Type\":1}}],\"SignalSources\":[{\"LastSignal\":0,\"Source\":{\"ID\":0,\"Type\":0}}]}", backgroundAnnouncementText, backgroundAnnouncementRevision, backgroundOfferDescription, backgroundOfferRevision, backgroundOfferName, backgroundOfferPrice, [[NSUserDefaults standardUserDefaults]valueForKey:#"PlaceID"], [[NSUserDefaults standardUserDefaults]valueForKey:#"UserID"], [[NSUserDefaults standardUserDefaults]valueForKey:#"UserID"]];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
//setup the request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", [jsonString length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
NSURLConnection *requestConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[requestConnection start];
}
else{
}
}
-(void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"Location Manager failed with error %#", error);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
currentLocation = [locations lastObject];
NSLog(#"Manager did update location");
}
-(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager{
NSLog(#"Location Manager Paused");
}
-(void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager{
NSLog(#"Location Manager Resumed");
}
#end
You shouldn't expect to run indefinitely. If you're a location app, then you should expect to be called when the device moves. But if the device isn't moving, then there's no reason for the OS to call you, and it won't.
You need to design your app so that it uses the minimum battery to achieve the user-desired behavior. To that end, if you have a boundary that you care about, you should set up a location region, and you will be woken up whenever the device moves into or out of that region. This is much, much cheaper than constantly watching the GPS.
If the user wants you to record every small movement, then you can set the location manager as you have (with kCLLocationAccuracyBest), but you still will only get called when the device moves. Since this will cause the maximum battery drain, make sure it's the only way to achieve the user's goal.
There is, by design, no way to request "Indefinite Background Time."
Related
I need to call a web service in every minute and parse the data when app is in background state.
Since the APP uses location service I have enabled background mode for update Location.
I tried calling location update by using a timer background task, but it not working.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"ending background task");
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
self.timer = [NSTimer scheduledTimerWithTimeInterval:60
target:self.locationManager
selector:#selector(startUpdatingLocation)
userInfo:nil
repeats:YES];
}
Is there any way to implement this with less battery consumption.
I referred this link
I'm not getting which solution is better here.
AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : NSObject {
// Instance member of our background task process
UIBackgroundTaskIdentifier bgTask;
}
#end
AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[BackgroundCleanupService getInstance] run];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
There are couple key lines in the above implementation:
The first is the line bgTask = [application beginBackgroundTaskWithExpirationHandler..., which requests additional time to run clean up tasks in the background.
The second is the final code block of the delegate method beginning with dispatch_async. It's basically checking whether there's time left to run an operation via the call [application backgroundTimeRemaining]. In this example, I'm looking to run the background service once but alternatively, you can use a loop checking on the backgroundTimeRemaining on each iteration.
The line [[BackgroundCleanupService getInstance] run] will be a call to our singleton service class, which we'll build right now.
With the app delegate ready to trigger our background task, we now need a service class that will communicate with the web server. In the following example, I'm going to a post a fictitious session key and parse a JSON encoded response. Also, I'm using two helpful libraries to make the request and deserialize the returned JSON, specifically JSONKit and ASIHttpRequest.
BackgroundCleanupService.h
#import <Foundation/Foundation.h>
#interface BackgroundCleanupService : NSObject
+ (BackgroundCleanupService *)getInstance;
- (void)run;
#end
BackgroundCleanupService.m
#import "BackgroundCleanupService.h"
#import "JSONKit.h"
#import "ASIHTTPRequest.h"
#implementation BackgroundCleanupService
/*
* The singleton instance. To get an instance, use
* the getInstance function.
*/
static BackgroundCleanupService *instance = NULL;
/**
* Singleton instance.
*/
+(BackgroundCleanupService *)getInstance {
#synchronized(self) {
if (instance == NULL) {
instance = [[self alloc] init];
}
}
return instance;
}
- (void)run {
NSURL* URL = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/user/%#/endsession", #"SESSIONKEY"]];
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:URL];
[request setTimeOutSeconds:20]; // 20 second timeout
// Handle request response
[request setCompletionBlock:^{
NSDictionary *responseDictionary = [[request responseData] objectFromJSONData];
// Assume service succeeded if JSON key "success" returned
if([responseDictionary objectForKey:#"success"]) {
NSLog(#"Session ended");
}
else {
NSLog(#"Error ending session");
}
}];
// Handle request failure
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Service error: %#", error.localizedDescription);
}];
// Start the request synchronously since the background service
// is already running on a background thread
[request startSynchronous];
}
#end
may be helped
How to remain getting the location continuously in the background in iOS8 and you must try your best to save electricity? Can anybody give me some advice?
In your project setting, Select Target and go to Capabilities, turn ON the background mode and tick the location updates and background fetch.
This will add background mode in your project plist.
Now, to get continuous location updates even in background, add this code in AppDelegate's applicationDidEnterBackground: method. This code will kill the background task every time and restart it. So, even when app is in background, you'll receive background location updates.
- (void)applicationDidEnterBackground:(UIApplication *)application {
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) { //Check if our iOS version supports multitasking I.E iOS 4
if ([[UIDevice currentDevice] isMultitaskingSupported]) { //Check if device supports mulitasking
UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
__block UIBackgroundTaskIdentifier background_task; //Create a task object
background_task = [application beginBackgroundTaskWithExpirationHandler: ^{
[application endBackgroundTask:background_task]; //Tell the system that we are done with the tasks
background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
//System will be shutting down the app at any point in time now
}];
}
}
}
Now to extend device battery life, you can use locationManager:didUpdateLocations: method as it is only called when location changes according to desired accuracy.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
if (location != nil) {
strLatitude = [NSString stringWithFormat:#"%f", location.coordinate.latitude];
strLongitude = [NSString stringWithFormat:#"%f", location.coordinate.longitude];
}
}
Found some Solution here
Study the example from Ray Wenderlich. The sample code works perfectly.
You can add timer to it by using this code snippet this may reduce battery consumption a bit :
-(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];
}
Currently on my iOS app, when the user exits to the home screen and goes back into the app, it requests a login credentials which is set in my AppDelegate. But what I am trying to do is if the user goes out of the app and back in within for example 2 minutes, the timer resets and the user does not need to input his password. When the user goes back into the app after 2 minutes, it will alert him to input the password again. Any help will be greatly appreciated. Thanks!
Use NSUserDefaults to store the NSDate in your app delegate
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"myDateKey"];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSDate *bgDate = (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey: #"myDateKey"];
if(fabs([bgDate timeIntervalSinceNow]) > 120.00) {
//logout
}
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"myDateKey"];
}
Update:
Good point by #mun chun if the app has to implement something to handle clock changes we can use something like this
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] setFloat: [[NSProcessInfo processInfo] systemUptime] forKey:#"myDateKey"];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
float bgTime = [[NSUserDefaults standardUserDefaults] floatForKey: #"myDateKey"];
if(fabs([[NSProcessInfo processInfo] systemUptime] - bgTime) > 120.00) {
//logout
}
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"myDateKey"];
}
Obviously once the phone restarts the time will be reset in that case we have to make sure we add validation. Also to note is that the myDateKey should be removed in appropriate application modes.
User may adjust the system time to earlier when the app is in background. It maybe not reliable to compare a stored time with current system time when app reopened.
We can use NSTimer+BackgroundTask to assure the amount of time elapsed.
In the applicationWillResignActive: delegate, setup a background task and a NSTimer.
When the timer fired (i.e. at 120 seconds), set the session expired, and end the background task.
When the app re-opened, in the applicationDidBecomeActive: delegate, check the session for request login if it expired.
static BOOL sessionActive;
static NSTimer *timer;
static UIBackgroundTaskIdentifier bgTask;
- (void)applicationWillResignActive:(UIApplication *)application
{
sessionActive = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:120.0 target:self selector:#selector(sessionExpired) userInfo:nil repeats:NO];
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{[self sessionExpired];}];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self cleanup];
if(!sessionActive)
{
//session expired, request login credentials
}
}
-(void)sessionExpired
{
[self cleanup];
sessionActive = NO;
}
-(void)cleanup
{
if([timer isValid]) [timer invalidate];
timer = nil;
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}
In didFinishLaunchingWithOptions a timer loop calling a function httpRequest every 1 minute interval.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//rest of code
NSTimer *notifyTimer = [NSTimer timerWithTimeInterval:60 target:self selector:#selector(httpRequest) userInfo:nil repeats:YES];//7200.0
[[NSRunLoop mainRunLoop] addTimer:notifyTimer forMode:NSDefaultRunLoopMode];
return YES;
}
After pressing home button application is going to background and calling function applicationDidEnterBackground so a background task is starting.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
__block UIBackgroundTaskIdentifier bgTask;
UIApplication *app = [UIApplication sharedApplication];
expirationHandler = ^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
};
bgTask = UIBackgroundTaskInvalid;
bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
}
By httpRequest function I am geting Y from web server after every 1 minute interval so a UILocalNotification fires after every seconds.
-(NSString *)httpRequest {
NSURL *url = [NSURL URLWithString:#"http://192.168.10.67/t.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *userAgent = [NSString stringWithFormat:#"bgTaskTest-IOS"];
[request setValue:userAgent forHTTPHeaderField:#"User-Agent"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
[request setHTTPMethod:#"GET"];
[request setTimeoutInterval:25];
NSURLResponse *response;
NSData *dataReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSString *stringReply = [[NSString alloc] initWithData:dataReply encoding:NSASCIIStringEncoding];
if ([stringReply isEqualToString:#"Y"]) {
[self showLocalNotification:nil]; //calling UILocalNotification
} else {
NSLog(#"%#",stringReply);
}
return stringReply;
}
Function showLocalNotification is calling after every 1 minute based on response of httpRequest function.
-(void)showLocalNotification {
NSString *msg = #"test message";
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *_localNotification = [[UILocalNotification alloc]init];
_localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];
_localNotification.timeZone = [NSTimeZone defaultTimeZone];
_localNotification.alertBody = msg;
_localNotification.soundName = UILocalNotificationDefaultSoundName;
_localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber]+1;
[[UIApplication sharedApplication] scheduleLocalNotification:_localNotification];
//[[UIApplication sharedApplication] presentLocalNotificationNow:_localNotification];
}
Everything is right, notification prompts after every 1 munite when application is in background.
But my problem is Background Task's life time is 10 mins, so after 10 mins no notification prompts. For this reason I am starting Background task again in beginBackgroundTaskWithExpirationHandler but my application kill at this time of restarting background task.
I couldn't able to use notification more than 10 mins when application is in background.
Please anybody help me.
There is no way (within the app store guidelines) to run arbitrary code in the background for longer than ten minutes (as you have noticed).
After 10 minutes your app will be suspended. There is a couple of ways around this, registering for other background modes (such as background audio, playing a silent sound file continuously) or background voip or background location services.
These hacky work around will keep your application unsuspended however your application will not get approved for the store.
in iOS7 there are advances to running code in the background, however nothing that will do what you want.
So if this is an app for your own use, use private API's or the method I suggested above, however if you want to get this app on the store, I'm afraid your out of luck.
My app got rejected by Apple three times, all with the same rejection letter, which is:
We found that your app uses a background mode but does not include
functionality that requires that mode to run persistently. This
behavior is not in compliance with the App Store Review Guidelines.
We noticed your app declares support for location in the
UIBackgroundModes key in your Info.plist but does not include features
that require persistent location.
It would be appropriate to add features that require location updates
while the app is in the background or remove the "location" setting
from the UIBackgroundModes key.
If you choose to add features that use the Location Background Mode,
please include the following battery use disclaimer in your
Application Description:
"Continued use of GPS running in the background can dramatically
decrease battery life."
For information on background modes, please refer to the section
"Executing Code in the Background" in the iOS Reference Library.
Now, as far as I know I am running on the background and "doing something"...
In my AppDelegate I have the following code in didFinishLaunchingWithOptions:
if ([[launchOptions allKeys] containsObject:UIApplicationLaunchOptionsLocationKey] &&
([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]))
{
id locationInBackground = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey];
if ([locationInBackground isKindOfClass:[CLLocation class]])
{
[self updateMyLocationToServer:locationInBackground];
}
else
{
//Keep updating location if significant changes
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
self.bgLocationManager = locationManager;
self.bgLocationManager.delegate = self;
self.bgLocationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[bgLocationManager startMonitoringSignificantLocationChanges];
}
}
The AppDelegate also starts a location manager and makes himself the delegate.
Then, I have the following code for handling the location updates on the background:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[self updateMyLocationToServer:newLocation];
}
-(void)updateMyLocationToServer:(CLLocation*)myNewLocation
{
// NSLog(#"Updating Location from the background");
NSString *fbID = [NSString stringWithString:[facebookDetails objectForKey:#"fbID"]];
NSString *firstName = [NSString stringWithString:[facebookDetails objectForKey:#"firstName"]];
NSString *lastName = [NSString stringWithString:[facebookDetails objectForKey:#"lastName"]];
NSString *urlString = [NSString stringWithFormat:#"MY_SERVER_API", fbID, myNewLocation.coordinate.latitude, myNewLocation.coordinate.longitude, firstName, lastName];
NSURL *url = [NSURL URLWithString:urlString];
__block ASIHTTPRequest *newRequest = [ASIHTTPRequest requestWithURL:url];
[newRequest setCompletionBlock:^{
}];
[newRequest setFailedBlock:^{
}];
// [newRequest setDelegate:self];
[newRequest startAsynchronous];
}
I also put a disclaimer in my app description page:
Intensive use of GPS running in the background can dramatically decrease battery life. For this reason, MY_APP_NAME runs on the background just listening for significant location changes.
Is there anything I'm missing here?
This question is old and already answered but you dont need the UIBackgroundModes key if you collect locations using the startMonitoringSignificantLocationChanges API
In locationManager:didUpdateToLocation:fromLocation: or in updateMyLocationToServer: You should check if application is in background state by eg.
[UIApplication sharedApplication].applicationState == UIApplicationStateBackground
And then if Your app is in background mode You should use eg.
backgroundTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:
^{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
}];
/*Write Your internet request code here*/
if (bgTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
bgTask = UIBackgroundTaskInvalid;
}
This way application should perform this task completely.
startMonitoringSignificantLocationChanges don't require a background mode registration. Only continuous location changes do.