Keith
Keith

Reputation: 1372

How to run iOS Core Location in background forever

I am creating a custom application for our office. I want this app to get the user's location every 5 minutes (or so) and send it to our server via json. I have it working however it won't run in the background longer than 10 minutes (that I can tell).

I have added "App registers for location updates" in Required background modes.

My code is in the AppDelegate, like this:

- (void)applicationDidBecomeActive:(UIApplication *)application
{

NSLog(@"Became active");

// Start location services
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 100.0f;
locationManager.delegate = self;

[locationManager stopMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];

}


- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{


BOOL isInBackground = NO;
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
{
    isInBackground = YES;

}
NSLog(@"Location Manager isInBackground: %hhd", isInBackground);

if (isInBackground)
{
    [self sendBackgroundLocationToServer:newLocation];
}
else
{
    [self sendDataToServer:newLocation];
}

}


-(void) sendBackgroundLocationToServer:(CLLocation *)location
{

bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    [[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];

// Send the data
[self sendDataToServer:location];

if (bgTask != UIBackgroundTaskInvalid)
{
    [[UIApplication sharedApplication] endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}
}

-(void) sendDataToServer:(CLLocation *)newLocation
{
NSLog(@"Sending Data to Server");
// Get battery level
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
float batteryLevel = [[UIDevice currentDevice] batteryLevel];

float lat = newLocation.coordinate.latitude;
float lng = newLocation.coordinate.longitude;
NSLog(@"Accuracy: %f", newLocation.horizontalAccuracy);
NSString *userId = [[NSUserDefaults standardUserDefaults] stringForKey:@"userId"];
NSString *post = [[NSString alloc] initWithFormat:@"login_id=%@&latitude=%f&longitude=%f&speed=%f&course=%f&battery_level=%f&horizontal_accuracy=%f&vertical_accuracy=%f",
                  userId,
                  lat,
                  lng,
                  [newLocation speed],
                  [newLocation course],
                  batteryLevel,
                  newLocation.horizontalAccuracy,
                  newLocation.verticalAccuracy];

NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSString *urlstring = [NSString stringWithFormat:@"%@webservice/post_logins_location.php", kBaseURL];
[request setURL:[NSURL URLWithString:urlstring]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];

NSError *error;
NSURLResponse *response;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
jsonResults = [NSJSONSerialization JSONObjectWithData:urlData options:kNilOptions error:&error];
NSLog(@"GPS Send results: %@", jsonResults);

_lastSentUpdateAt = [NSDate date];
}

I have also tried it with startMonitoringSignificantLocationChanges and removing the _lastSentUpdateAt completely. However I'm still getting the same results. My question now is, can json send data from the background after 10 minutes? Right now my phone has been running for over an hour and the Location Services icon is still active for my app. However I'm not seeing any data hit my server with updates. Once I actually opened my app, it did receive updates which makes me believe that there is an issue sending the data in the background. Or is there something else going on?

Upvotes: 1

Views: 2333

Answers (1)

jaredsinclair
jaredsinclair

Reputation: 12687

Read the documentation and watch the WWDC presentations related to "registering for significant location updates." They have made improvements and changes to the officially recommended ways of doing this while being prudent with power consumption.

Specifically, there is no way to get the background location at a time interval you specify. Significant location updates fire at the discretion of the OS, and are influenced by many factors beyond your app's control.

If all you're trying to do is keep the app from being terminated in the background, you'll need to declare that kind of background mode in the plist for your app. It's under "Info" in Xcode, under "App registers for location updates" I think.

Upvotes: 2

Related Questions