I'm trying to respond to location updates when my app is terminated. Apple's documentation states:
iOS supports the delivery of location events to apps that are suspended or no longer running.
It also states that startUpdatingLocation
Can use location updates in background mode YES
However, my didUpdateToLocation
method is only called when the app is running in the foreground or in the background. When I terminate the app, it never wakes up to handle location updates. I've tested this on several simulated devices (iPhone 6, 7, 8, X) as well as a real iPhone 5s. I've also confirmed setAllowsBackgroundLocationUpdates
is being called.
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