应用程序终止时未调用 CLLocationManager `didUpdateToLocation`

CLLocationManager `didUpdateToLocation` not called when app is terminated

我正在尝试在我的应用程序终止时响应位置更新。 Apple's documentation 状态:

iOS supports the delivery of location events to apps that are suspended or no longer running.

它还指出 startUpdatingLocation

Can use location updates in background mode YES

但是,我的 didUpdateToLocation 方法仅在应用 运行 在前台或后台时调用。当我终止应用程序时,它永远不会醒来处理位置更新。我已经在几个模拟设备(iPhone 6、7、8、X)以及真实的 iPhone 5s 上对此进行了测试。我还确认正在调用 setAllowsBackgroundLocationUpdates

AppDelegate.m

#import "AppDelegate.h"
#import "RNFIRMessaging.h"
#import <CoreLocation/CoreLocation.h>

#import <React/RCTBridgeModule.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "NoteManager.h"

@implementation AppDelegate {
  UIApplication *_app;
  NoteManager *_noteManager;
  CLLocationManager* _locationManager;
}

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  NSLog(@"--- Initializing application");
  _app = application;

  id<RCTBridgeDelegate> moduleInitialiser = self;
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:launchOptions];

  RCTRootView *rootView = [[RCTRootView alloc]
    initWithBridge:bridge
    moduleName:@"GoNote"
    initialProperties:nil
  ];
  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  [FIRApp configure];
  [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
  [self setupLocationManager];

  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
  // return [NSURL URLWithString:@"http://192.168.1.177:8081/index.ios.bundle?platform=ios"];
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
}

- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge {
  NSLog(@"--- extraModulesForBridge");
  // Initialize our native modules here
  _noteManager = [[NoteManager alloc] initWithApp:_app];
  return @[
    _noteManager
  ];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
  NSLog(@"--- pushNotifications willPresentNotification");
  [RNFIRMessaging willPresentNotification:notification withCompletionHandler:completionHandler];
}

#if defined(__IPHONE_11_0)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
  NSLog(@"--- pushNotifications didReceiveNotificationResponse");
  [RNFIRMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}
#else
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler {
  NSLog(@"--- pushNotifications didReceiveNotificationResponse");
  [RNFIRMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}
#endif

//You can skip this method if you don't want to use local notification
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
  NSLog(@"--- pushNotifications didReceiveLocalNotification");
  [RNFIRMessaging didReceiveLocalNotification:notification];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
  NSLog(@"--- pushNotifications didReceiveLocalNotification");
  [RNFIRMessaging didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

- (void) applicationDidEnterBackground:(UIApplication *)application {
  NSLog(@"--- applicationDidEnterBackground");
  [_locationManager stopUpdatingLocation];

  __block UIBackgroundTaskIdentifier bgTask = [_app beginBackgroundTaskWithExpirationHandler:^{
    bgTask = UIBackgroundTaskInvalid;
  }];

  [NSTimer
    scheduledTimerWithTimeInterval: 10.0
    target: self
    selector: @selector(startTrackingBg)
    userInfo: nil
    repeats: YES
  ];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError*)error {
  NSLog(@"--- (NoteManager) locationManager didFailWithError %@", error);
}

- (void) setupLocationManager {
  NSLog(@"--- setupLocationManager");
  CLLocationManager* locationManager = _locationManager = [[CLLocationManager alloc] init];
  if([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    NSLog(@"--- setAllowsBackgroundLocationUpdates:YES");
    [locationManager setAllowsBackgroundLocationUpdates:YES];
  } else {
    NSLog(@"--- setAllowsBackgroundLocationUpdates:NO");
  }
  [locationManager setDelegate:self];
  [locationManager requestAlwaysAuthorization];
  [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
  [locationManager setDistanceFilter:10];
  [locationManager setPausesLocationUpdatesAutomatically:NO];
  [locationManager startUpdatingLocation];
}

- (void) startTrackingBg {
#if !TARGET_OS_TV
  NSLog(@"--- startTrackingBg");
  [_locationManager startUpdatingLocation];
#endif
}

- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
  NSLog(@"--- didUpdateToLocation");
  if(_noteManager != nil) {
    [_noteManager updateLocation:newLocation];
  }
}

@end

AppDelegate.h

#import <UIKit/UIKit.h>
#import <React/RCTBridgeDelegate.h>
#import <CoreLocation/CoreLocation.h>
@import UserNotifications;

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate, RCTBridgeDelegate, CLLocationManagerDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

这并不完全符合您的要求。当您使用

监控重大位置变化时,位置更新会起作用

startMonitoringSignificantLocationChanges()

在此处阅读此答案,其中有人正在尝试几乎相同的事情 - Restart location updates from the background

您可以在此处阅读实现 https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html