Get & Send iPhone Location to Server via JSON with iOS 7

By | October 14, 2013

I recently made an app that gets a user’s location and sends it to our server. The app will update every 1000 meters when it is active and will update only during major changes when it is inactive. The location will not always been 100% correct or up to date (depending on a lot of circumstances) but if you’re wanting to get an approximate location of your users, this should work pretty well.

This code lives in my AppDelegate since I want it to run no matter what they’re doing in my app.


- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Start location services
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;

// Only report to location manager if the user has traveled 1000 meters
locationManager.distanceFilter = 1000.0f;
locationManager.delegate = self;
locationManager.activityType = CLActivityTypeAutomotiveNavigation;

[locationManager stopMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{

// Check if running in background or not
BOOL isInBackground = NO;
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
isInBackground = YES;
}
NSLog(@"Location Manager isInBackground: %hhd", isInBackground);

if (isInBackground) {

// If we're running in the background, run sendBackgroundLocationToServer
         [self sendBackgroundLocationToServer:[locations lastObject]];
     } else {
         // If we're not in the background wait till the GPS is accurate to send it to the server
if ([[locations lastObject] horizontalAccuracy] < 100.0f) {
             [self sendDataToServer:[locations lastObject]];
         }
     }

}

-(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");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // I also want to send the battery level to the 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"];

    // This is the data I am sending to the server
    // I am sending a userID that the server recognizes
    // I am sending the latitude and longitude of the user as well as their speed course and battery life
    // I am also sending the horizontal & vertical accuracy so I can see how accurate the gps location was
    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];

     if (!error) {
         jsonResults = [NSJSONSerialization JSONObjectWithData:urlData options:kNilOptions error:&error];
         NSLog(@"GPS Send results: %@", jsonResults);
    } else {
         NSLog(@"Error sending GPS data to server");
    }
 });
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSLog(@"Went to Background");
// Only monitor significant changes
    [locationManager startMonitoringSignificantLocationChanges];
}

I chose to use startMonitoringSignificantLocationChanges when in the background. From what I’ve read this only updates when the phone changes radio towers and is not very accurate. For my purposes, this was fine. I’m just trying to get an idea on where the phone is.

And that should do it. Please let me know if I have any syntax errors (I’m sure I do).

Leave a Reply

Your email address will not be published. Required fields are marked *