Correctly passes localNotification to app on wakeup

Summary:
Currently if an RN app is started in response to a remote notification, that notification's data is available on startup via `PushNotificationIOS.popInitialNotification()`. However, if the app is started in response to a "local" notification, that information is never passed in. This PR modifies the `popInitialNotification` behavior so it will return the notification used to launch the app, no matter if it was local or remote.

I've tested this change in my app and ensured that when the app is woken up with a `localNotification` it's passed in to `PushNotificationIOS.popInitialNotification`. I've also tested that the `localNotification` event continues working as before.
Closes https://github.com/facebook/react-native/pull/7765

Differential Revision: D3417267

Pulled By: nicklockwood

fbshipit-source-id: 0b5b432e9a75dda7d3c50289a3bf0f1c1ffcf061
This commit is contained in:
Kyle Corbitt 2016-06-10 05:15:54 -07:00 committed by Facebook Github Bot 8
parent 6236a593d8
commit 57d45235ec
1 changed files with 48 additions and 27 deletions

View File

@ -31,10 +31,6 @@ NSString *const RCTRegisterUserNotificationSettings = @"RegisterUserNotification
NSString *const RCTErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
@interface RCTPushNotificationManager ()
@property (nonatomic, copy) RCTPromiseResolveBlock requestPermissionsResolveBlock;
@end
@implementation RCTConvert (UILocalNotification)
+ (UILocalNotification *)UILocalNotification:(id)json
@ -56,12 +52,15 @@ NSString *const RCTErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMI
@end
@implementation RCTPushNotificationManager
{
RCTPromiseResolveBlock _requestPermissionsResolveBlock;
}
static NSDictionary *formatLocalNotification(UILocalNotification *notification)
static NSDictionary *RCTFormatLocalNotification(UILocalNotification *notification)
{
NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary];
if (notification.fireDate) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
formattedLocalNotification[@"fireDate"] = fireDateString;
@ -77,6 +76,11 @@ static NSDictionary *formatLocalNotification(UILocalNotification *notification)
RCT_EXPORT_MODULE()
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
@ -114,8 +118,18 @@ RCT_EXPORT_MODULE()
- (NSDictionary<NSString *, id> *)constantsToExport
{
NSDictionary<NSString *, id> *initialNotification =
[self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
return @{@"initialNotification": RCTNullIfNil(initialNotification)};
self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
UILocalNotification *initialLocalNotification =
self.bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
if (initialNotification) {
return @{@"initialNotification": [initialNotification copy]};
} else if (initialLocalNotification) {
return @{@"initialNotification": RCTFormatLocalNotification(initialLocalNotification)};
} else {
return @{@"initialNotification": (id)kCFNull};
}
}
+ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
@ -150,16 +164,9 @@ RCT_EXPORT_MODULE()
+ (void)didReceiveLocalNotification:(UILocalNotification *)notification
{
NSMutableDictionary *details = [NSMutableDictionary new];
if (notification.alertBody) {
details[@"alertBody"] = notification.alertBody;
}
if (notification.userInfo) {
details[@"userInfo"] = RCTJSONClean(notification.userInfo);
}
[[NSNotificationCenter defaultCenter] postNotificationName:RCTLocalNotificationReceived
object:self
userInfo:details];
userInfo:RCTFormatLocalNotification(notification)];
}
- (void)handleLocalNotificationReceived:(NSNotification *)notification
@ -179,7 +186,7 @@ RCT_EXPORT_MODULE()
- (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
{
if (self.requestPermissionsResolveBlock == nil) {
if (_requestPermissionsResolveBlock == nil) {
return;
}
@ -190,8 +197,8 @@ RCT_EXPORT_MODULE()
@"badge": @((notificationSettings.types & UIUserNotificationTypeBadge) > 0),
};
self.requestPermissionsResolveBlock(notificationTypes);
self.requestPermissionsResolveBlock = nil;
_requestPermissionsResolveBlock(notificationTypes);
_requestPermissionsResolveBlock = nil;
}
/**
@ -219,12 +226,12 @@ RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions
return;
}
if (self.requestPermissionsResolveBlock != nil) {
if (_requestPermissionsResolveBlock != nil) {
RCTLogError(@"Cannot call requestPermissions twice before the first has returned.");
return;
}
self.requestPermissionsResolveBlock = resolve;
_requestPermissionsResolveBlock = resolve;
UIUserNotificationType types = UIUserNotificationTypeNone;
if (permissions) {
@ -298,11 +305,15 @@ RCT_EXPORT_METHOD(cancelAllLocalNotifications)
[RCTSharedApplication() cancelAllLocalNotifications];
}
RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary *)userInfo)
RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary<NSString *, id> *)userInfo)
{
for (UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications) {
__block BOOL matchesAll = YES;
NSDictionary *notificationInfo = notification.userInfo;
NSDictionary<NSString *, id> *notificationInfo = notification.userInfo;
// Note: we do this with a loop instead of just `isEqualToDictionary:`
// because we only require that all specified userInfo values match the
// notificationInfo values - notificationInfo may contain additional values
// which we don't care about.
[userInfo enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if (![notificationInfo[key] isEqual:obj]) {
matchesAll = NO;
@ -319,16 +330,26 @@ RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve
reject:(__unused RCTPromiseRejectBlock)reject)
{
NSDictionary<NSString *, id> *initialNotification =
[self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
resolve(RCTNullIfNil(initialNotification));
self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
UILocalNotification *initialLocalNotification =
self.bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
if (initialNotification) {
resolve([initialNotification copy]);
} else if (initialLocalNotification) {
resolve(RCTFormatLocalNotification(initialLocalNotification));
} else {
resolve((id)kCFNull);
}
}
RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTResponseSenderBlock)callback)
{
NSArray<UILocalNotification *> *scheduledLocalNotifications = [UIApplication sharedApplication].scheduledLocalNotifications;
NSMutableArray *formattedScheduledLocalNotifications = [[NSMutableArray alloc] init];
NSMutableArray<NSDictionary *> *formattedScheduledLocalNotifications = [NSMutableArray new];
for (UILocalNotification *notification in scheduledLocalNotifications) {
[formattedScheduledLocalNotifications addObject:formatLocalNotification(notification)];
[formattedScheduledLocalNotifications addObject:RCTFormatLocalNotification(notification)];
}
callback(@[formattedScheduledLocalNotifications]);
}