Skip to content

Commit

Permalink
Correctly passes localNotification to app on wakeup
Browse files Browse the repository at this point in the history
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 facebook#7765

Differential Revision: D3417267

Pulled By: nicklockwood

fbshipit-source-id: 0b5b432e9a75dda7d3c50289a3bf0f1c1ffcf061
  • Loading branch information
corbt authored and Facebook Github Bot 8 committed Jun 10, 2016
1 parent 6236a59 commit 57d4523
Showing 1 changed file with 48 additions and 27 deletions.
75 changes: 48 additions & 27 deletions Libraries/PushNotificationIOS/RCTPushNotificationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@

NSString *const RCTErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";

@interface RCTPushNotificationManager ()
@property (nonatomic, copy) RCTPromiseResolveBlock requestPermissionsResolveBlock;
@end

@implementation RCTConvert (UILocalNotification)

+ (UILocalNotification *)UILocalNotification:(id)json
Expand All @@ -56,12 +52,15 @@ + (UILocalNotification *)UILocalNotification:(id)json
@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;
Expand All @@ -77,6 +76,11 @@ @implementation RCTPushNotificationManager

RCT_EXPORT_MODULE()

- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}

- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
Expand Down Expand Up @@ -114,8 +118,18 @@ - (void)stopObserving
- (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
Expand Down Expand Up @@ -150,16 +164,9 @@ + (void)didReceiveRemoteNotification:(NSDictionary *)notification

+ (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
Expand All @@ -179,7 +186,7 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification

- (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
{
if (self.requestPermissionsResolveBlock == nil) {
if (_requestPermissionsResolveBlock == nil) {
return;
}

Expand All @@ -190,8 +197,8 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
@"badge": @((notificationSettings.types & UIUserNotificationTypeBadge) > 0),
};

self.requestPermissionsResolveBlock(notificationTypes);
self.requestPermissionsResolveBlock = nil;
_requestPermissionsResolveBlock(notificationTypes);
_requestPermissionsResolveBlock = nil;
}

/**
Expand Down Expand Up @@ -219,12 +226,12 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
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) {
Expand Down Expand Up @@ -298,11 +305,15 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
[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;
Expand All @@ -319,16 +330,26 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
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]);
}
Expand Down

0 comments on commit 57d4523

Please sign in to comment.