简体   繁体   中英

iOS9 startMonitoringSignificantLocationChanges doesn't launch app when terminated?

I'm working on an iPhone app that needs to send the current location to a server so it knows what push notifications to send. It doesn't have to be very precise, startMonitoringSignificantLocationChanges is perfect for my needs.

This all works well as long as the app is running on screen or in the background. However if I kill/terminate the app it doesn't work anymore. From what I understand the app should be automatically relaunched with the special UIApplicationLaunchOptionsLocationKey as launch option. However the app doesn't relaunch (at least not in simulator).

I've read some stuff here too: Behaviour for significant change location API when terminated/suspended?

Does the automatic relaunching only work when the app is terminated from suspended state by the system and not when you manually kill the app? I also tried the special info.plist UIApplicationExitsOnSuspend which also terminates the app when it goes into the background. It doesn't get relaunched then either.

Is there a way to simulate the app being terminated by the system in the simulator?

What happens after an iOS update when the phone has restarted? Is there a way to make sure that the app will get relaunched?

An app is relaunched by an SLC regardless of how it was killed provided when it was killed at least one CLLocationManager had called startMonitoringSignificantLocationChanges. There is one caveat to this - in version iOS7.0(.x) it was broken. It started working again in iOS7.1+.

To get this working requires that you complete a few steps.

  1. In you project capabilities you must enable the background mode location updates because you want to be woken in the background.
  2. You need to add the key NSLocationAlwaysUsageDescription to the info.plist containing a description of why you want to always be able to use location in the background.
  3. In the code you must request authorization from the user to always use location
  4. In the code you must request that location updates continue to be delivered while in the background
  5. In the code you must start monitoring for significant location changes

Here is an example:

AppDelegate,h

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>

@property (strong, nonatomic) UIWindow *window;
@property CLLocationManager* locationMgr;

@end

AppDelegate.m

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize locationMgr;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    NSLog(@"app launching");

    locationMgr = [[CLLocationManager alloc] init];
    [locationMgr setDelegate:self];
    // Added in iOS8
    if([locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)])
        [locationMgr requestAlwaysAuthorization];
    // Added in iOS9
    if([locationMgr respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
        [locationMgr setAllowsBackgroundLocationUpdates:YES];
    [locationMgr startMonitoringSignificantLocationChanges];

    return YES;
}

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"app delegate received significant location change");
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[UIApplication sharedApplication] applicationIconBadgeNumber]+1];
}

@end

The first time you run the app on your device, click on OK to allow the app to use your location in the background when it is requested. Then double click the home button and swipe the app off the task switcher to kill it. Click home, then swipe up from the bottom of the screen to open the Control Center and turn on Airplane Mode, wait a few seconds, then turn off airplane mode. Watch the badge counter increment on your app.

It was launched by iOS on an SLC.

One gotcha I would like to add. If you create two CLLocationManager instances and call startMonitoringSignificantLocationChanges on both, then call stopMonitoringSignificantLocationChanges on one. Even though the other CLLocationManager will continue to receive SLC events while the app continues to run, when you app exits for any reason, it will not be relaunched.

It seems the last call before exit sets the relaunch behaviour.

start, start, stop, exit - app doesn't relaunch on SLC.

start, start, stop start, exit - app does relaunch on SLC.

I've answered a question like this. You can check my answer on the link below.

https://stackoverflow.com/a/35722254/3368791 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM