I have an issue where an app is registering for background location updates which it receives until the device hibernates, but then after the device resumes from hibernation the location updates do not resume.
The app is very very simple as its a test to measure the effect of location updates on battery life.
I created the app using the single view application template and:
- Added the code posted below to the app delegate (that's it, no other code)
- Added the location updates background mode
- Added coreLocation.framework
When I launch the app then move it to the background then didUpdateLocations: continues to get called continuously for about 15-20 minutes and getDataUsage() executes every few seconds.
Then after about 15-20 minutes the device hibernates (I'm monitoring activity on Organizer's console). However after waking the device up the app never receives any didUpdateLocations: calls.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.timeThatDataMonitoringStarted = [NSDate date];
self.initialDataValuesSet = NO;
CLLocationDegrees degreesFilter = 0.1;
[self.locationManager setHeadingFilter: degreesFilter];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 10;
[self.locationManager startUpdatingLocation];
[self getDataUsage];
return YES;
}
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"******************** LOCATION didUpdateLocations ***************");
static NSDate* previousDate;
static int count = 0;
if (previousDate)
{
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:previousDate];
NSLog(@" LOCATION: count: %d time since last update: %f", ++count, timeInterval);
}
previousDate = [NSDate date];
}
- (void) getDataUsage
{
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate: self.timeThatDataMonitoringStarted];
NSLog(@"********* GETTING DATA USAGE. Elapsed time: %f **************",elapsedTime);
NSArray *data = [self getDataCounters];
NSNumber *wifiSentSinceBoot = (NSNumber*)data[0];
NSNumber *wifiReceivedSinceBoot = (NSNumber*)data[1];
NSNumber *wwanSentSinceBoot = (NSNumber*)data[2];
NSNumber *wwanReceivedSinceBoot = (NSNumber*)data[3];
int wifiSentSinceBootAsInt = [wifiSentSinceBoot intValue];
int wifiReceivedSinceBootAsInt = [wifiReceivedSinceBoot intValue];
int wWanSentSinceBootAsInt = [wwanSentSinceBoot intValue];
int wWanReceivedSinceBootAsInt = [wwanReceivedSinceBoot intValue];
static int initialWifiSent;
static int initialWifiReceived;
static int initialWWanSent;
static int initialWWanReceived;
if (!self.initialDataValuesSet)
{
self.initialDataValuesSet = YES;
initialWifiSent = wifiSentSinceBootAsInt;
initialWifiReceived = wifiReceivedSinceBootAsInt;
initialWWanSent = wWanSentSinceBootAsInt;
initialWWanReceived = wWanReceivedSinceBootAsInt;
}
int wifiSentSinceLastRetrieval = wifiSentSinceBootAsInt - initialWifiSent;
int wifiReceivedSinceLastRetrieval = wifiReceivedSinceBootAsInt - initialWifiReceived;
int wWanSentSinceLastRetrieval = wWanSentSinceBootAsInt - initialWWanSent;
int wWanReceivedSinceLastRetrieval = wWanReceivedSinceBootAsInt - initialWWanReceived;
uint dataUsed = wifiSentSinceLastRetrieval + wifiReceivedSinceLastRetrieval + wWanSentSinceLastRetrieval + wWanReceivedSinceLastRetrieval;
NSLog(@"Total data: %d", dataUsed);
[self performSelector:@selector(getDataUsage) withObject:nil afterDelay:3];
}
- (NSArray *) getDataCounters
{
BOOL success;
struct ifaddrs *addrs;
const struct ifaddrs *cursor;
const struct if_data *networkStatisc;
int WiFiSent = 0;
int WiFiReceived = 0;
int WWANSent = 0;
int WWANReceived = 0;
NSString *name=[[NSString alloc]init];
success = getifaddrs(&addrs) == 0;
if (success)
{
cursor = addrs;
while (cursor != NULL)
{
name=[NSString stringWithFormat:@"%s",cursor->ifa_name];
// NSLog(@"ifa_name %s == %@\n", cursor->ifa_name,name);
// names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
if (cursor->ifa_addr->sa_family == AF_LINK)
{
if ([name hasPrefix:@"en"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
WiFiSent+=networkStatisc->ifi_obytes;
WiFiReceived+=networkStatisc->ifi_ibytes;
// NSLog(@"WiFiSent %d ==%d",WiFiSent,networkStatisc->ifi_obytes);
// NSLog(@"WiFiReceived %d ==%d",WiFiReceived,networkStatisc->ifi_ibytes);
}
if ([name hasPrefix:@"pdp_ip"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
WWANSent+=networkStatisc->ifi_obytes;
WWANReceived+=networkStatisc->ifi_ibytes;
// NSLog(@"WWANSent %d ==%d",WWANSent,networkStatisc->ifi_obytes);
// NSLog(@"WWANReceived %d ==%d",WWANReceived,networkStatisc->ifi_ibytes);
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return [NSArray arrayWithObjects:[NSNumber numberWithInt:WiFiSent], [NSNumber numberWithInt:WiFiReceived],[NSNumber numberWithInt:WWANSent],[NSNumber numberWithInt:WWANReceived], nil];
}
Note I'm using the term "hibernation" not to refer to the app state but to the device state. If you observe the device activity in Organizer's console then after a while the device as a whole starts to shut down. I'm calling this hibernation as I don't know what the actual iOS term is, and by hibernation I also don't mean Auto-Lock and the screen sleeping. This is a separate activity after that, I'm presuming the telephony and GPS chips etc. are powering down. Anyway after this "hibernation" phase has been reached, then if you resume activity on the device is when I am not getting the didUpdateLocations.