4

I am trying to get locations while my app is in the background. Everything works great when I am using my app. I can also switch to any other app (even the home screen) and the locations still come in. If I am using my phone but my app is in the background location updates seem to come in just fine as long as my phone is active (not locked).

However if I lock the phone and I come back after about 10 minutes the location icon in the status bar and my app is no longer getting location updates.

I have checked for an app crash and there is no crash report. My app also still appears in the app list so I don't think it crashed.

Should GPS stay on forever if I have asked for 'Always' permission. Or does the OS turn it off after the phone has been asleep for a while?

Here is are the entries in my plist:

<key>NSLocationAlwaysUsageDescription</key>
<string></string>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>

And here is a screenshot of background location services on:

enter image description here

Here is my custom class that is the location manager delegate:

@interface LocationDelegate ()
    @property (nonatomic, strong) CLLocationManager *locationManager;
@end

@implementation LocationDelegate

+ (instancetype) singleton {
    static LocationDelegate *delegate = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        delegate = [[self alloc] init];
    });
    return delegate;
}

- (id) init {
    if (self = [super init]) {
        // for now filter and accuracy are based on the same preference
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
        _locationManager.delegate = self;

        // Check for iOS 8
        if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
            [_locationManager requestAlwaysAuthorization];
        }

    return self;
}

Notice that it is a singleton. Does that matter? Is this class getting cleaned up after my app has been in the background for a while or suspended? From what I have read I don't think singletons like this get cleaned up as they are strong references so I don't think that is the problem...but I really have no idea why I stop getting locations after a certain amount of time.

EDIT:

Seems that my location manager is pausing location updates after some time. The big issue that that I am not getting a resume call.

I have the activityType set to the default of

CLActivityTypeOther

I can try other activityTypes to see if that will make a difference. However I am relying on my app to work for walking, and driving.

I think I am running into the same problem as this:

iPhone GPS in background never resumes after pause

Community
  • 1
  • 1
lostintranslation
  • 23,756
  • 50
  • 159
  • 262

3 Answers3

3

No, it does not necessarily continue to run in the background. By default, pausesLocationUpdatesAutomatically is set to YES this in conjunction with the activityType (if set) help the OS determine when it is safe to pause location updates to conserve power. You can implement locationManagerDidPauseLocationUpdates: delegate to log if the OS paused your updates.

Also, just to be clear, setting requestAlwaysAuthorization doesn't mean the locationManager will keep running, it just means your app can launch the locationManager from foreground or background or suspended modes.

rmp
  • 3,503
  • 1
  • 17
  • 26
  • pausesLocationUpdatesAutomatically set to YES should be fine. As long as if I start to move again the location manager starts back up "unpauses", which is not happening. I will check though to see if it is pausing and not restarting for some reason. Also when you say 'doesn't mean the locationManager will keep running', what is the proper way to keep the location manager running? If you need me to post more code let me know. – lostintranslation Jul 02 '15 at 02:43
  • Yes, locationManager should start updates again if you start moving again. When it restarts, it should call `locationManagerDidResumeLocationUpdates:` However, it may take some movement before it starts again based on your distance filter and accuracy settings. You should also look at setting an `activityType` on the locationManager to assist the OS in knowing when to pause updates. In your case you may want to look at setting it to `CLActivityTypeAutomotiveNavigation` – rmp Jul 02 '15 at 03:02
  • My app uses location data for auto and pedestrian. Is setting the activityType to CLActivityTypeAutomotiveNavigation going to cause problems when users are walking? Currently it is set to the default 'CLActivityTypeOther'. Does look like my location manager is not resuming after signifigant movement – lostintranslation Jul 02 '15 at 04:18
  • since you are using your app for both walking and auto you should give the user the ability to set what they are using it for, like the Maps app. You can then toggle the type between `CLActivityTypeFitness` and `CLActivityTypeAutomotiveNavigation` – rmp Jul 02 '15 at 14:37
  • Don't think it matters unfortunately no matter distance filter and activity type iOS does not resume after a pause. Same problem as outlined in other SO post I linked. Answer for now it to now allow pausing. – lostintranslation Jul 03 '15 at 01:12
  • Have you tried restarting the location manager from the didPause delegate? I guess though if you don't want it to pause you can do as you said and not allow pausing. That will be a serious hit on the battery though. – rmp Jul 03 '15 at 01:40
0

Yes, it should stay on as long as you allow it in the BackgroundModes, request the requestAlwaysAuthorization and add the NSLocationAlwaysUsageDescription. However, the NSLocationAlwaysUsageDescription must have description, your XML looks like you don't have any. Obviously, you also need to call startUpdatingLocation.

If you think your singleton might be part of the problem, try moving the code to the appDelegate.

MirekE
  • 11,515
  • 5
  • 35
  • 28
  • NSLocationAlwaysUsageDescription is ok to be a blank string. I will look more into the singleton for sure. – lostintranslation Jul 02 '15 at 02:41
  • 1
    I compared it to my (Swift) code and I don't think I am doing anything differently, except that I don't have the singleton and for iOS9 I added also `locationManager.allowsBackgroundLocationUpdates = true`. The app does background updates properly. – MirekE Jul 02 '15 at 03:28
0

Restart after pause would have same effect as not letting it pause. Yes it's a battery hit but my only option if I want it to run when user starts moving again.

lostintranslation
  • 23,756
  • 50
  • 159
  • 262