iOS App Background Location (Push Notifications)

2019-04-16 23:45发布

问题:

I face an issue where my app requires the users location when they receive a push notification while the app is running in the background.

After doing a bit of reading I'm under the impression that this isn't possible, i.e:

1) App in background

2) Push notification received

3) Get users location and execute block of code.

I found this post on here that suggests you can run a task every N amount of minutes to get the users location. So using this I could check say every ten minutes which would work but it would be a waste of the users battery if I kept activating the GPS. Therefore I was wondering can I tell within my background task if the user has any push notification waiting for my app? That way I would check if they did every ten minutes and only activate the GPS if they did.

Perhaps I'm going about this all the wrong way, I would really appreciate any advice. Sorry for not having any of the code for the background task yet as I'm still trying to get it to work.

[UPDATE]

Thanks Dustin for your advice. After a bit of testing I've decided to go with an easier option. I am now using the Apple Significant Location Changes. I store the changes in an array, I've set this to only update if the last change was greater than 10min ago. Then when the app becomes active I match the closest time in the array to the time the push notification was sent and use that location.

回答1:

As discussed I used alternative solution, here it is:

Under viewDidLoad or didFinishingLaunchingWithOptions add:

locationsLogged = [[NSMutableArray alloc] init];
lastLocationTime = [[NSDate alloc] init]
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

Under applicationDidEnterBackground add:

[locationManager startMonitoringSignificantLocationChanges];

Add:

-(void) storeLocations:(CLLocation *)location
{
bgTask = [[UIApplication sharedApplication]
          beginBackgroundTaskWithExpirationHandler:
          ^{
              [[UIApplication sharedApplication] endBackgroundTask:bgTask];
               }];

[locationsLogged addObject:location];

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


 -(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
BOOL isInBackground = NO;
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
{
    isInBackground = YES;
} 


NSDate *now = [NSDate date];
NSTimeInterval diff = [now timeIntervalSinceDate:lastLocationTime];


if ((int)diff > 600) {

    if (isInBackground)
    {
        [lastLocationTime release];
        lastLocationTime = [[NSDate alloc] init];
        [self storeLocations:newLocation];
    }
    else
    {
        // ...
    }
}
}

Then on applicationDidBecomeActive you can use whatever logic you need to apply location information.