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.
Related
I want to rang beacons in the background. With background i mean when the phone goes to lock screen. I want the app to continue ranging beacons. The problem i have now is that the code never finds beacons. I have two beacons who is working but the AppDelegate don't find them. When i run the same code in a ViewController, it finds the beacons and displays them. How can i do it?
#interface BDAppDelegate () <AXABeaconManagerDelegate>
#end
#implementation BDAppDelegate {
NSMutableDictionary *beaconRegions;
NSMutableDictionary *detectBeacons;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:#"MyUUID"] identifier:#"微信"];
[AXABeaconManager sharedManager].beaconDelegate = self;
[[AXABeaconManager sharedManager] requestAlwaysAuthorization];
[[AXABeaconManager sharedManager] startRangingBeaconsInRegion:beaconRegion];
self->beaconRegions = [[NSMutableDictionary alloc] init];
self->detectBeacons = [[NSMutableDictionary alloc] init];
while (detectBeacons.count < 10) {
NSLog(#"Rows in detectBeacons %lu", (unsigned long)beaconRegions.count);
}
self->beaconRegions[beaconRegion] = [NSArray array];
}
- (void)didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
self->beaconRegions[region] = beacons;
NSMutableArray *allBeacons = [NSMutableArray array];
for (NSArray *regionResult in [self->beaconRegions allValues])
{
[allBeacons addObjectsFromArray:regionResult];
}
NSPredicate *pre = [NSPredicate predicateWithFormat:#"accuracy != -1"];
NSArray *rights = [allBeacons filteredArrayUsingPredicate:pre];
NSString * str = #"accuracy";
self->detectBeacons[str] = rights;
}
#end
On iOS, apps are limited to ranging for 5 seconds in the background. This timer is restarted each time the app is put to the background, or when a beacon monitoring event (entered region / exited region) fires. The good news is that you can extend the time allowed to range beacons in the background to 3 minutes after each of these events.
I put together a blog post that shows you how to do it here.
For CLLocationManager there is a method startMonitoringForRegion(CLBeaconRegion *):beaconRegion
which should be added before we start startRangingBeaconsInRegion.
So if your AXABeaconManager class is from CLLocationManager add this:
[[AXABeaconManager sharedManager] startMonitoringForRegion:beaconRegion];
Otherwise:
Create a CLLocationManager object locationManager and initialize it then add start monitoring like below.
[self.locationManager startMonitoringForRegion:beaconRegion];
before you startRangingBeaconsInRegion
Discussion: startMonitoringForRegion
You must call this method once for each region you want to monitor. If an existing region with the same identifier is already being monitored by the app, the old region is replaced by the new one. The regions you add using this method are shared by all location manager objects in your app and stored in the monitoredRegions property.
for more refer here
ranging for beacons is an operation that consumes a lot of battery and iOS won't allow you to do it endlessly in the BG (most of the time. there are cases, where it works)
what you gotta do is call iOS your doing BG work:
UIBackgroundTaskIdentifier token = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Ranging for region %# killed", region.identifier);
}];
if(token == UIBackgroundTaskInvalid) {
NSLog(#"cant start background task");
}
THEN do whatever
when done, call endBackgroundTask
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];
}
In My Application.
I used following code to Update Location Coordinates to Server with 1 min time Interval. Its working fine for some times 10 to 20 Hours. but its some time stopped Periodically Please help me.
UIApplication *application1 = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier background_task;
background_task = [application1 beginBackgroundTaskWithExpirationHandler:^ {
[application1 endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//### background task starts
//NSLog(#"Running in the background\n");
while(TRUE)
{
[locationManager startMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
NSUserDefaults *addValue=[NSUserDefaults standardUserDefaults];
NSString *oldLat=[addValue stringForKey:#"OLD_LAT"];
NSString *oldLong=[addValue stringForKey:#"OLD_LONG"];
CLLocationManager *manager = [[CLLocationManager alloc] init];
manager.desiredAccuracy=kCLLocationAccuracyBestForNavigation;
NSString *locLat = [NSString stringWithFormat:#"%lf",manager.location.coordinate.latitude];
NSString * locLong = [NSString stringWithFormat:#"%lf",manager.location.coordinate.longitude];
float lat_new=[locLat floatValue];
float lang_new=[locLong floatValue];
float lat_old=[oldLat floatValue];
float lang_old=[oldLong floatValue];
if (lat_new>0 && lang_new>0) {
//NSLog(#"location changed");
[addValue setObject:locLat forKey:#"OLD_LAT"];
[addValue setObject:locLong forKey:#"OLD_LONG"];
float from_lat_value=[locLat floatValue];
float from_long_value=[locLong floatValue];
locLat=[NSString stringWithFormat:#"%f",from_lat_value];
locLong=[NSString stringWithFormat:#"%f",from_long_value];
//NSLog(#"LST:%#,%#",locLat,locLong);
NSUserDefaults *addLat=[NSUserDefaults standardUserDefaults];
[addLat setObject:locLat forKey:#"FROM_LAT"];
[addLat setObject:locLong forKey:#"FROM_LONG"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/user/insertUserLocation",CONFIG_BASE_URL]];
// //NSLog(#"URL:%#",url);
__block ASIFormDataRequest *requestmethod = [ASIFormDataRequest requestWithURL:url];
NSUserDefaults *userValue=[NSUserDefaults standardUserDefaults];
NSString *deviceToken=[NSString stringWithFormat:#"%#",[userValue objectForKey:#"DEVICE_TOKEN"]];
NSString *loginValidation=[userValue objectForKey:#"USER_ID"];
[requestmethod setValidatesSecureCertificate:NO];
[requestmethod setPostValue:deviceToken forKey:#"deviceToken"];
[requestmethod setPostValue:locLat forKey:#"latitude"];
[requestmethod setPostValue:locLong forKey:#"longitude"];
[requestmethod setPostValue:loginValidation forKey:#"userID"];
[requestmethod setTimeOutSeconds:180];
[requestmethod setCompletionBlock:^{
NSString *responseString23 = [requestmethod responseString];
//NSLog(#"BACKGROUND RESPONCE:%#",responseString23);
}];
[requestmethod setFailedBlock:^{
NSError *error = [requestmethod error];
if ([[NSString stringWithFormat:#"%#",error.localizedDescription] isEqualToString:#"The request timed out"]||[[NSString stringWithFormat:#"%#",error.localizedDescription] isEqualToString:#"Please connect online to use the app"])
{
}
else
{
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Alert-360"
message:[NSString stringWithFormat:#"%#",error.localizedDescription] delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
// [self endBackgroundUpdateTask];
}];
[requestmethod startAsynchronous];
}
[locationManager stopMonitoringSignificantLocationChanges];
[locationManager stopUpdatingLocation];
}
[NSThread sleepForTimeInterval:BACKGROUND_INTERVAL_CHECKIN]; //wait for 1 sec
//Clean up code. Tell the system that we are done.
[application1 endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
//NSLog(#"background Task finished");
});
Check my commends.
After App Enters background, we can get Latitude and longitude values.but we can't post this data to server. Apple restricted this.
I calculated both Foreground and Background time remaining code, I got following results
Foreground:
Foreground time remaining >>>>: 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 seconds (2147483647 mins)
Background:
Background time remaining >>>>: 159.223682 seconds (2 mins)
For my final commend: we can't run background location update to server long time.
I used to receive the same crashes in my gps trackers that run in the background. I fixed those crashes by checking the values validity before every call. I found some of my variables are nil. Calling selectors of null variables will most probably kick the execution outside the task function with no rescheduling.
Guarding my calls with a null check on every task call fixed my issue. You can also add as much logs as you can; and leave it running for a while and then check where the crash happen by checking your logs. Beside the normal nslog output I used to have an external shared document logging text file as well. You should be able to have all your application logs in that file separated at any time in the future. Make sure to turn that logging off before sending to market.
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."
I'm building an app with Region monitoring. It works fine in foreground but once the app is sent in background, it's not behaving as expected: it does call didEnter and didExit but as soon as it starts executing the callbacks it stops. In these callback methods i need to poll a server and persist didExitRegion and/or didEnterRegion status. As soon as I put the app in foreground again, any queued request starts and completes.
Any idea?
I'm using ios5.1 and ios6 on iphone 4
When you get called in the background in
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
(or ...exit)
just setup whatever you need for the server call (variables, payload for the server etc etc).
Before the actual sending start a
self.bgTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
self.bgTaskId = UIBackgroundTaskInvalid;
somelogger(#"ran out of time for background task");
// remember that we failed for the next time the app comes to the foreground
}];
Then do the actual sending with the HTTP framework of your choice and in the completion handlers reset the background task with
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
Example using AFNetworking:
[self.httpClient postPath:#"state" parameters:#{#"abc": abc, #"value": val, #"h": h, #"app":myAppName , #"version": myAppVersion }
success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.response.statusCode != 200) {
DDLogVerbose(#"response was not 200. error: %i", operation.response.statusCode);
} else {
DDLogVerbose(#"success");
}
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DDLogVerbose(#"request error %#, current retry count %d", error, retryCount );
// start our own retry mechanism
if (retryCount < MAX_RETRIES) {
retryCount++;
double delayInSeconds = RETRY_INTERVAL * (1 + (double)retryCount/10);
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// try again
});
} else {
// final
[[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
// remember failure when app comes back to foreground
}
}];
I am using a
#property (assign, nonatomic) UIBackgroundTaskIdentifier bgTaskId;
to store the background identifier.
The whole mechanism is explained in http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW28
you have to request additional time if you want to stay alive.
see applle docu on background mode. There is a method for that.
generally you are not "allowed" to stay active in background for any task. only for specific ones, like GPS.
try to request additional background time after each region update.
If you havent already add 'location' to the UIBackgroundModes of your Info.plist. As a second idea I'd use AFNetworking which is widely popular and has backgrounding support. That means it will deal with setting up the parameters to tell the OS that it will "finish this thing before I go back to sleep".