Peter Lapisu
Peter Lapisu

Reputation: 21005

Cocoa, how to get better GPS monitoring, while app is in background

We have implemented the significant location change monitoring, using the startMonitoringSignificantLocationChanges together with LocationUpdates in Background modes selected, this enables us to get location while in background

However the location is quite raw, as the SignificantLocationChange happens only infrequently...

We noticed however, that apps like Endomondo (running app), or Sygic (navigation app) can run in background and yet they offer high accurate GPS data..., how is it possible? i know that you can do a background task, but this will run maybe for 10 minutes, but yet these applications provide accurate GPS for long period of time

Upvotes: 0

Views: 134

Answers (3)

Alex Pavlov
Alex Pavlov

Reputation: 1001

There are two distinct ways to monitor location - GPS and Wifi/Cell tower triangulation. While Apple provides quite a few details about internal implementation, the Core Location framework often behaves AS IF it has two location managers (GPS and Wifi/Cell) running independently. Again, I am not saying this is exactly how it is implemented under the hood, but seeing the Core Location framework that way explains most of the "issues", happening when the framework behaves not in the way you expect.

The significant location change service activates Wifi/Cell location manager. It does not use the GPS location manager at all. The significant location changes are at least 500 meters and at least 5 minutes. Yes, even if you move quick, you should not expect location updates more often than once every 5 minutes.

If you need "accurate GPS data", as your question implies, you have to use GPS location manager, that is standard location updates, which are requested via startUpdatingLocation method. There are multiple ways to optimize battery consumption by trading precision, but again - if you need GPS accuracy, you have to use standard location updates. Do not waste your time on tricks, the significant location updates will not give you current location on the spot - it monitors changes, it is not intended for location readings.

Make sure you requested background updates (UIBackgroundModes key in Info.plist) and initiated standard location updates while your app runs in foreground, this way updates will continue even when your app is inactive.

Upvotes: 1

Abhinav
Abhinav

Reputation: 38162

From Apple docs:

In iOS, regions associated with your app are tracked at all times, including when the app isn’t running. If a region boundary is crossed while an app isn’t running, that app is relaunched into the background to handle the event. Similarly, if the app is suspended when the event occurs, it’s woken up and given a short amount of time (around 10 seconds) to handle the event. When necessary, an app can request more background execution time using the beginBackgroundTaskWithExpirationHandler: method of the UIApplication class.

Upvotes: 0

baydi
baydi

Reputation: 988

Try This code

 @try {

    UIApplication* application = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier background_task;
    background_task = [application beginBackgroundTaskWithExpirationHandler:^ {
        [application endBackgroundTask: background_task];
        background_task = UIBackgroundTaskInvalid;
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        MJGLocationManager* locat= [MJGLocationManager sharedManager];
        locat.desiredAccuracy=kCLLocationAccuracyHundredMeters;
        [locat setDelegate:self];
        if ([locat respondsToSelector:@selector(requestAlwaysAuthorization)])
            [locat requestAlwaysAuthorization];
        [locat stopUpdatingLocation];
        [locat startUpdatingLocation];
        [application endBackgroundTask: background_task];
        background_task = UIBackgroundTaskInvalid;
    });
}

@catch (NSException *exception) {

    MJGLocationManager* locat= [MJGLocationManager sharedManager];
    locat.desiredAccuracy=kCLLocationAccuracyHundredMeters;
    [locat setDelegate:self];
    if ([locat respondsToSelector:@selector(requestAlwaysAuthorization)])
        [locat requestAlwaysAuthorization];
    [locat stopUpdatingLocation];
    [locat startUpdatingLocation];
}

`

Here MJGLocationManager is my location manager class you can use yours

Upvotes: 0

Related Questions