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

标签 ios objective-c cocoa-touch geolocation core-location

<分区>

我正在尝试在我的应用程序终止时响应位置更新。 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

关于ios - 应用程序终止时未调用 CLLocationManager `didUpdateToLocation`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46796744/

上一篇:android - 如何使用 Adob​​e air - AS3 在静音模式下检测设备并与之交互

下一篇:ios - 如何按 id 或月份 : Descending (Latest Post First)? 对数组进行排序

相关文章:

ios - Objective-C:用作子函数的 block 的命名实践

ios - 为什么我们仍然在 swift ios 应用程序中使用 NSDictionary 和 NSArrays?

ios - 使用 afnetworking 一次下载一个文件

ios - UINavigationController popViewControllerAnimated 缓慢过渡

iphone - MKPinAnnotationView:是否有超过三种颜色可用?

objective-c - Objective-c 中的奇怪类型转换

iOS 应用内购买 - 无法解锁内容,因为该功能在另一个 View Controller 中

objective-c - 在应用程序启动时设置带有复选框的 BOOL 值?

iphone - 调用了 "StopUpdatingLocation"但 GPS 箭头没有消失

objective-c - 如何在 Objective-C 类中包装 .c native 库方法