From 235cffd8a421304d17e2e418904cfd048c90f920 Mon Sep 17 00:00:00 2001 From: yogevbd Date: Tue, 9 Jul 2019 00:42:38 +0300 Subject: [PATCH] WIP --- RNNotifications/RCTConvert+Notifications.h | 33 +++------ RNNotifications/RCTConvert+Notifications.m | 52 +++++++++++++- RNNotifications/RNBridgeModule.m | 14 ++-- RNNotifications/RNCommandsHandler.h | 10 ++- RNNotifications/RNCommandsHandler.m | 71 ++++++------------- RNNotifications/RNEventEmitter.h | 1 - RNNotifications/RNEventEmitter.m | 7 +- RNNotifications/RNNotificationCenter.h | 14 ++++ RNNotifications/RNNotificationCenter.m | 68 ++++++++++++++++++ .../RNNotificationCenterListener.m | 12 +--- RNNotifications/RNNotificationEventHandler.h | 5 +- RNNotifications/RNNotificationEventHandler.m | 33 +++------ RNNotifications/RNNotificationParser.h | 9 +++ RNNotifications/RNNotificationParser.m | 31 ++++++++ RNNotifications/RNNotifications.h | 5 +- RNNotifications/RNNotifications.m | 16 ++++- .../RNNotifications.xcodeproj/project.pbxproj | 16 +++++ RNNotifications/RNNotificationsStore.h | 6 +- RNNotifications/RNNotificationsStore.m | 17 ++++- RNNotifications/RNPushKit.h | 2 +- RNNotifications/RNPushKit.m | 6 +- RNNotifications/RNPushKitEventListener.m | 2 +- docs/advancedIos.md | 6 +- example/index.ios.js | 8 ++- .../AppIcon.appiconset/Contents.json | 15 ++++ lib/src/index.ios.js | 6 +- lib/src/notification.ios.js | 30 ++++---- package.json | 2 +- 28 files changed, 341 insertions(+), 156 deletions(-) create mode 100644 RNNotifications/RNNotificationCenter.h create mode 100644 RNNotifications/RNNotificationCenter.m create mode 100644 RNNotifications/RNNotificationParser.h create mode 100644 RNNotifications/RNNotificationParser.m diff --git a/RNNotifications/RCTConvert+Notifications.h b/RNNotifications/RCTConvert+Notifications.h index aaff9dc..519ce17 100644 --- a/RNNotifications/RCTConvert+Notifications.h +++ b/RNNotifications/RCTConvert+Notifications.h @@ -1,31 +1,6 @@ #import "RCTConvert.h" @import UserNotifications; -static NSDictionary *RCTFormatUNNotification(UNNotification *notification) -{ - NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary]; - UNNotificationContent *content = notification.request.content; - - formattedNotification[@"identifier"] = notification.request.identifier; - - if (notification.date) { - NSDateFormatter *formatter = [NSDateFormatter new]; - [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"]; - NSString *dateString = [formatter stringFromDate:notification.date]; - formattedNotification[@"fireDate"] = dateString; - } - - formattedNotification[@"alertTitle"] = RCTNullIfNil(content.title); - formattedNotification[@"alertBody"] = RCTNullIfNil(content.body); - formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier); - formattedNotification[@"thread-id"] = RCTNullIfNil(content.threadIdentifier); - formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo)); - - return formattedNotification; -} - -@import UserNotifications; - @interface RCTConvert (UIUserNotificationActivationMode) @end @@ -53,3 +28,11 @@ static NSDictionary *RCTFormatUNNotification(UNNotification *notification) @interface RCTConvert (UNNotificationRequest) + (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSString*)notificationId; @end + +@interface RCTConvert (UNNotification) ++ (NSDictionary *)UNNotificationPayload:(UNNotification *)notification; +@end + +@interface RCTConvert (UNNotificationPresentationOptions) ++ (UNNotificationPresentationOptions)UNNotificationPresentationOptions:(id)json; +@end diff --git a/RNNotifications/RCTConvert+Notifications.m b/RNNotifications/RCTConvert+Notifications.m index 2a330e1..431cc4e 100644 --- a/RNNotifications/RCTConvert+Notifications.m +++ b/RNNotifications/RCTConvert+Notifications.m @@ -39,9 +39,15 @@ RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{ @implementation RCTConvert (UNMutableUserNotificationAction) + (UNNotificationAction *)UNMutableUserNotificationAction:(id)json { + UNNotificationAction* action; NSDictionary *details = [self NSDictionary:json]; - UNNotificationAction* action = [UNNotificationAction actionWithIdentifier:details[@"identifier"] title:details[@"title"] options:[RCTConvert UNUserNotificationActionOptions:details]]; + if (details[@"textInput"]) { + action = [UNTextInputNotificationAction actionWithIdentifier:details[@"identifier"] title:details[@"title"] options:[RCTConvert UNUserNotificationActionOptions:details] textInputButtonTitle:details[@"textInput"][@"buttonTitle"] textInputPlaceholder:details[@"textInput"][@"placeholder"]]; + } else { + action = [UNNotificationAction actionWithIdentifier:details[@"identifier"] title:details[@"title"] options:[RCTConvert UNUserNotificationActionOptions:details]]; + } + // action.behavior = [RCTConvert UIUserNotificationActionBehavior:details[@"behavior"]]; return action; @@ -119,3 +125,47 @@ RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{ content:content trigger:trigger]; } @end + +@implementation RCTConvert (UNNotification) ++ (NSDictionary *)UNNotificationPayload:(UNNotification *)notification { + NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary]; + UNNotificationContent *content = notification.request.content; + + formattedNotification[@"identifier"] = notification.request.identifier; + + if (notification.date) { + NSDateFormatter *formatter = [NSDateFormatter new]; + [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"]; + NSString *dateString = [formatter stringFromDate:notification.date]; + formattedNotification[@"date"] = dateString; + } + + formattedNotification[@"title"] = RCTNullIfNil(content.title); + formattedNotification[@"body"] = RCTNullIfNil(content.body); + formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier); + formattedNotification[@"thread"] = RCTNullIfNil(content.threadIdentifier); + formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo)); + + return formattedNotification; +} + +@end + +@implementation RCTConvert (UNNotificationPresentationOptions) + ++ (UNNotificationPresentationOptions)UNNotificationPresentationOptions:(id)json { + UNNotificationPresentationOptions options = UNNotificationPresentationOptionNone; + if ([RCTConvert BOOL:json[@"alert"]]) { + options = options | UNNotificationPresentationOptionAlert; + } + if ([RCTConvert BOOL:json[@"badge"]]) { + options = options | UNNotificationPresentationOptionBadge; + } + if ([RCTConvert BOOL:json[@"sound"]]) { + options = options | UNNotificationPresentationOptionSound; + } + + return options; +} + +@end diff --git a/RNNotifications/RNBridgeModule.m b/RNNotifications/RNBridgeModule.m index 9850b49..9d43e66 100644 --- a/RNNotifications/RNBridgeModule.m +++ b/RNNotifications/RNBridgeModule.m @@ -18,10 +18,6 @@ RCT_EXPORT_MODULE(); return self; } -- (dispatch_queue_t)methodQueue { - return dispatch_get_main_queue(); -} - + (BOOL)requiresMainQueueSetup { return YES; } @@ -41,8 +37,12 @@ RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve reject: [_commandsHandler getInitialNotification:resolve reject:reject]; } -RCT_EXPORT_METHOD(completionHandler:(NSString *)completionKey) { - [_commandsHandler completionHandler:completionKey]; +RCT_EXPORT_METHOD(finishHandlingAction:(NSString *)completionKey) { + [_commandsHandler finishHandlingAction:completionKey]; +} + +RCT_EXPORT_METHOD(finishPresentingNotification:(NSString *)completionKey presentingOptions:(NSDictionary *)presentingOptions) { + [_commandsHandler finishPresentingNotification:completionKey presentingOptions:presentingOptions]; } RCT_EXPORT_METHOD(abandonPermissions) { @@ -62,7 +62,7 @@ RCT_EXPORT_METHOD(setBadgesCount:(int)count) { } RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification withId:(NSString *)notificationId) { - [_commandsHandler localNotification:notification withId:notificationId]; + [_commandsHandler sendLocalNotification:notification withId:notificationId]; } RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId) { diff --git a/RNNotifications/RNCommandsHandler.h b/RNNotifications/RNCommandsHandler.h index 1ce85e9..2447268 100644 --- a/RNNotifications/RNCommandsHandler.h +++ b/RNNotifications/RNCommandsHandler.h @@ -1,14 +1,18 @@ #import #import -#import "RNNotificationsStore.h" +#import "RNNotificationCenter.h" @interface RNCommandsHandler : NSObject +- (instancetype)init; + - (void)requestPermissionsWithCategories:(NSArray *)json; - (void)getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)completionHandler:(NSString *)completionKey; +- (void)finishHandlingAction:(NSString *)completionKey; + +- (void)finishPresentingNotification:(NSString *)completionKey presentingOptions:(NSDictionary *)presentingOptions; - (void)abandonPermissions; @@ -18,7 +22,7 @@ - (void)setBadgesCount:(int)count; -- (void)localNotification:(NSDictionary *)notification withId:(NSString *)notificationId; +- (void)sendLocalNotification:(NSDictionary *)notification withId:(NSString *)notificationId; - (void)cancelLocalNotification:(NSString *)notificationId; diff --git a/RNNotifications/RNCommandsHandler.m b/RNNotifications/RNCommandsHandler.m index f2b9538..d5fca11 100644 --- a/RNNotifications/RNCommandsHandler.m +++ b/RNNotifications/RNCommandsHandler.m @@ -1,48 +1,31 @@ #import "RNCommandsHandler.h" #import "RNNotifications.h" #import "RCTConvert+Notifications.h" -#import "RNPushKit.h" @implementation RNCommandsHandler { - RNPushKit* _pushKit; + RNNotificationCenter* _notificationCenter; +} + +- (instancetype)init { + self = [super init]; + _notificationCenter = [RNNotificationCenter new]; + return self; } - (void)requestPermissionsWithCategories:(NSArray *)json { - NSMutableSet* categories = nil; - - if ([json count] > 0) { - categories = [NSMutableSet new]; - for (NSDictionary* categoryJson in json) { - [categories addObject:[RCTConvert UNMutableUserNotificationCategory:categoryJson]]; - } - } - [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categories]; - UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert); - [UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { - if (error) { - - } else { - if (granted) { - [UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { - if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) { - dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] registerForRemoteNotifications]; - }); - } - }]; - } else { - - } - } - }]; + [_notificationCenter requestPermissionsWithCategories:json]; } - (void)getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { resolve([[RNNotifications sharedInstance] initialNotification]); } -- (void)completionHandler:(NSString *)completionKey { - [[RNNotifications sharedInstance] finishHandleNotificationKey:completionKey]; +- (void)finishHandlingAction:(NSString *)completionKey { + [[RNNotifications sharedInstance] finishHandleActionKey:completionKey]; +} + +- (void)finishPresentingNotification:(NSString *)completionKey presentingOptions:(NSDictionary *)presentingOptions { + [[RNNotifications sharedInstance] finishHandleNotificationKey:completionKey presentingOptions:[RCTConvert UNNotificationPresentationOptions:presentingOptions]]; } - (void)abandonPermissions { @@ -50,7 +33,7 @@ } - (void)registerPushKit { - _pushKit = [[RNPushKit alloc] initWithPushKitEventListener:[RNPushKitEventListener new]]; + [[RNNotifications sharedInstance] initializePushKit]; } - (void)getBadgesCount:(RCTResponseSenderBlock)callback { @@ -62,14 +45,12 @@ [[UIApplication sharedApplication] setApplicationIconBadgeNumber:count]; } -- (void)localNotification:(NSDictionary *)notification withId:(NSString *)notificationId { - UNNotificationRequest* localNotification = [RCTConvert UNNotificationRequest:notification withId:notificationId]; - [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotification withCompletionHandler:nil]; +- (void)sendLocalNotification:(NSDictionary *)notification withId:(NSString *)notificationId { + [_notificationCenter sendLocalNotification:notification withId:notificationId]; } - (void)cancelLocalNotification:(NSString *)notificationId { - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - [center removePendingNotificationRequestsWithIdentifiers:@[notificationId]]; + [_notificationCenter cancelLocalNotification:notificationId]; } - (void)cancelAllLocalNotifications { @@ -91,25 +72,15 @@ } - (void)removeAllDeliveredNotifications { - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - [center removeAllDeliveredNotifications]; + [_notificationCenter removeAllDeliveredNotifications]; } - (void)removeDeliveredNotifications:(NSArray *)identifiers { - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - [center removeDeliveredNotificationsWithIdentifiers:identifiers]; + [_notificationCenter removeDeliveredNotifications:identifiers]; } - (void)getDeliveredNotifications:(RCTResponseSenderBlock)callback { - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - [center getDeliveredNotificationsWithCompletionHandler:^(NSArray * _Nonnull notifications) { - NSMutableArray *formattedNotifications = [NSMutableArray new]; - - for (UNNotification *notification in notifications) { - [formattedNotifications addObject:RCTFormatUNNotification(notification)]; - } - callback(@[formattedNotifications]); - }]; + [_notificationCenter getDeliveredNotifications:callback]; } @end diff --git a/RNNotifications/RNEventEmitter.h b/RNNotifications/RNEventEmitter.h index 33e8db7..e2008e2 100644 --- a/RNNotifications/RNEventEmitter.h +++ b/RNNotifications/RNEventEmitter.h @@ -6,7 +6,6 @@ static NSString* const RNPushKitRegistered = @"pushKitRegistered"; static NSString* const RNNotificationReceivedForeground = @"notificationReceivedForeground"; static NSString* const RNNotificationReceivedBackground = @"notificationReceivedBackground"; static NSString* const RNNotificationOpened = @"notificationOpened"; -static NSString* const RNActionTriggered = @"notificationActionTriggered"; @interface RNEventEmitter : RCTEventEmitter diff --git a/RNNotifications/RNEventEmitter.m b/RNNotifications/RNEventEmitter.m index 695bca0..f8c9edc 100644 --- a/RNNotifications/RNEventEmitter.m +++ b/RNNotifications/RNEventEmitter.m @@ -10,8 +10,7 @@ RCT_EXPORT_MODULE(); RNPushKitRegistered, RNNotificationReceivedForeground, RNNotificationReceivedBackground, - RNNotificationOpened, - RNActionTriggered]; + RNNotificationOpened]; } - (instancetype)init { @@ -22,6 +21,10 @@ RCT_EXPORT_MODULE(); return self; } ++ (BOOL)requiresMainQueueSetup { + return YES; +} + # pragma mark public + (void)sendEvent:(NSString *)event body:(NSDictionary *)body { diff --git a/RNNotifications/RNNotificationCenter.h b/RNNotifications/RNNotificationCenter.h new file mode 100644 index 0000000..b5da6a3 --- /dev/null +++ b/RNNotifications/RNNotificationCenter.h @@ -0,0 +1,14 @@ +#import +#import +@import UserNotifications; + +@interface RNNotificationCenter : NSObject + +- (void)requestPermissionsWithCategories:(NSArray *)json; +- (void)sendLocalNotification:(NSDictionary *)notification withId:(NSString *)notificationId; +- (void)cancelLocalNotification:(NSString *)notificationId; +- (void)removeAllDeliveredNotifications; +- (void)removeDeliveredNotifications:(NSArray *)identifiers; +- (void)getDeliveredNotifications:(RCTResponseSenderBlock)callback; + +@end diff --git a/RNNotifications/RNNotificationCenter.m b/RNNotifications/RNNotificationCenter.m new file mode 100644 index 0000000..803ba56 --- /dev/null +++ b/RNNotifications/RNNotificationCenter.m @@ -0,0 +1,68 @@ +#import "RNNotificationCenter.h" +#import "RCTConvert+Notifications.h" + +@implementation RNNotificationCenter + +- (void)requestPermissionsWithCategories:(NSArray *)json { + NSMutableSet* categories = nil; + + if ([json count] > 0) { + categories = [NSMutableSet new]; + for (NSDictionary* categoryJson in json) { + [categories addObject:[RCTConvert UNMutableUserNotificationCategory:categoryJson]]; + } + } + [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categories]; + UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert); + [UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (error) { + + } else { + if (granted) { + [UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { + if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) { + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] registerForRemoteNotifications]; + }); + } + }]; + } else { + + } + } + }]; +} + +- (void)sendLocalNotification:(NSDictionary *)notification withId:(NSString *)notificationId { + UNNotificationRequest* localNotification = [RCTConvert UNNotificationRequest:notification withId:notificationId]; + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotification withCompletionHandler:nil]; +} + +- (void)cancelLocalNotification:(NSString *)notificationId { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center removePendingNotificationRequestsWithIdentifiers:@[notificationId]]; +} + +- (void)removeAllDeliveredNotifications { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center removeAllDeliveredNotifications]; +} + +- (void)removeDeliveredNotifications:(NSArray *)identifiers { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center removeDeliveredNotificationsWithIdentifiers:identifiers]; +} + +- (void)getDeliveredNotifications:(RCTResponseSenderBlock)callback { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center getDeliveredNotificationsWithCompletionHandler:^(NSArray * _Nonnull notifications) { + NSMutableArray *formattedNotifications = [NSMutableArray new]; + + for (UNNotification *notification in notifications) { + [formattedNotifications addObject:[RCTConvert UNNotificationPayload:notification]]; + } + callback(@[formattedNotifications]); + }]; +} + +@end diff --git a/RNNotifications/RNNotificationCenterListener.m b/RNNotifications/RNNotificationCenterListener.m index 487c873..3df99a2 100644 --- a/RNNotifications/RNNotificationCenterListener.m +++ b/RNNotifications/RNNotificationCenterListener.m @@ -1,4 +1,5 @@ #import "RNNotificationCenterListener.h" +#import "RCTConvert+Notifications.h" @implementation RNNotificationCenterListener { RNNotificationEventHandler* _notificationEventHandler; @@ -13,18 +14,11 @@ } - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { - [_notificationEventHandler didReceiveForegroundPayload:notification.request.content.userInfo]; + [_notificationEventHandler didReceiveForegroundNotification:notification withCompletionHandler:completionHandler]; } - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { - if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) { - [_notificationEventHandler didOpenNotificationPayload:response.notification.request.content.userInfo]; - } else if ([response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) { - - } else { - NSString* responseText = [response isKindOfClass:[UNTextInputNotificationResponse class]] ? ((UNTextInputNotificationResponse *)response).userText : nil; - [_notificationEventHandler handleActionWithIdentifier:response.actionIdentifier forPayload:response.notification.request.content.userInfo withResponse:responseText completionHandler:completionHandler]; - } + [_notificationEventHandler didReceiveNotificationResponse:response completionHandler:completionHandler]; } @end diff --git a/RNNotifications/RNNotificationEventHandler.h b/RNNotifications/RNNotificationEventHandler.h index 7b6cc0e..413e0cd 100644 --- a/RNNotifications/RNNotificationEventHandler.h +++ b/RNNotifications/RNNotificationEventHandler.h @@ -10,8 +10,7 @@ - (void)didRegisterForRemoteNotificationsWithDeviceToken:(id)deviceToken; - (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; -- (void)didReceiveForegroundPayload:(NSDictionary *)payload; -- (void)didOpenNotificationPayload:(NSDictionary *)payload; -- (void)handleActionWithIdentifier:(NSString *)identifier forPayload:(NSDictionary *)payload withResponse:(NSString *)response completionHandler:(void (^)())completionHandler; +- (void)didReceiveForegroundNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler; +- (void)didReceiveNotificationResponse:(UNNotificationResponse *)notificationResponse completionHandler:(void (^)())completionHandler; @end diff --git a/RNNotifications/RNNotificationEventHandler.m b/RNNotifications/RNNotificationEventHandler.m index 48f03c2..1fc1b21 100644 --- a/RNNotifications/RNNotificationEventHandler.m +++ b/RNNotifications/RNNotificationEventHandler.m @@ -1,6 +1,8 @@ #import "RNNotificationEventHandler.h" #import "RNEventEmitter.h" #import "RNUtils.h" +#import "RCTConvert+Notifications.h" +#import "RNNotificationParser.h" @implementation RNNotificationEventHandler { RNNotificationsStore* _store; @@ -21,33 +23,14 @@ [RNEventEmitter sendEvent:RNRegistrationFailed body:@{@"code": [NSNumber numberWithInteger:error.code], @"domain": error.domain, @"localizedDescription": error.localizedDescription}]; } -- (void)didReceiveForegroundPayload:(NSDictionary *)payload { - [RNEventEmitter sendEvent:RNNotificationReceivedForeground body:payload]; +- (void)didReceiveForegroundNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { + [_store setPresentationCompletionHandler:completionHandler withCompletionKey:notification.request.identifier]; + [RNEventEmitter sendEvent:RNNotificationReceivedForeground body:[RNNotificationParser parseNotification:notification]]; } -- (void)didOpenNotificationPayload:(NSDictionary *)payload { - [RNEventEmitter sendEvent:RNNotificationOpened body:payload]; -} - -- (void)handleActionWithIdentifier:(NSString *)identifier forPayload:(NSDictionary *)payload withResponse:(NSString *)response completionHandler:(void (^)())completionHandler { - [self emitNotificationActionForIdentifier:identifier response:response userInfo:payload completionHandler:completionHandler]; -} - -- (void)emitNotificationActionForIdentifier:(NSString *)identifier response:(NSString *)response userInfo:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { - NSString* completionKey = [NSString stringWithFormat:@"%@.%@", identifier, [NSString stringWithFormat:@"%ldd", (long)[[NSDate date] timeIntervalSince1970]]]; - NSMutableDictionary* info = [[NSMutableDictionary alloc] initWithDictionary:@{ @"identifier": identifier, @"completionKey": completionKey }]; - - if (response != NULL) { - info[@"text"] = response; - } - - // add notification custom data - if (userInfo != NULL) { - info[@"notification"] = userInfo; - } - - [_store setCompletionHandler:completionHandler withCompletionKey:identifier]; - [RNEventEmitter sendEvent:RNActionTriggered body:userInfo]; +- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)())completionHandler { + [_store setActionCompletionHandler:completionHandler withCompletionKey:response.notification.request.identifier]; + [RNEventEmitter sendEvent:RNNotificationOpened body:[RNNotificationParser parseNotificationResponse:response]]; } @end diff --git a/RNNotifications/RNNotificationParser.h b/RNNotifications/RNNotificationParser.h new file mode 100644 index 0000000..6397d20 --- /dev/null +++ b/RNNotifications/RNNotificationParser.h @@ -0,0 +1,9 @@ +#import +@import UserNotifications; + +@interface RNNotificationParser : NSObject + ++ (NSDictionary *)parseNotificationResponse:(UNNotificationResponse *)response; ++ (NSDictionary *)parseNotification:(UNNotification *)notification; + +@end diff --git a/RNNotifications/RNNotificationParser.m b/RNNotifications/RNNotificationParser.m new file mode 100644 index 0000000..aee4cad --- /dev/null +++ b/RNNotifications/RNNotificationParser.m @@ -0,0 +1,31 @@ +#import "RNNotificationParser.h" +#import "RCTConvert+Notifications.h" + +@implementation RNNotificationParser + ++ (NSDictionary *)parseNotification:(UNNotification *)notification { + NSDictionary* notificationDict = @{@"identifier": notification.request.identifier, + @"payload": [RCTConvert UNNotificationPayload:notification] + }; + + return notificationDict; +} + ++ (NSDictionary *)parseNotificationResponse:(UNNotificationResponse *)response { + NSDictionary* responseDict = @{@"payload": [RCTConvert UNNotificationPayload:response.notification], @"identifier": response.notification.request.identifier, @"action": [self parseNotificationResponseAction:response]}; + + return responseDict; +} + ++ (NSDictionary *)parseNotificationResponseAction:(UNNotificationResponse *)response { + NSMutableDictionary* responseAction = [NSMutableDictionary dictionaryWithDictionary:@{@"identifier": response.actionIdentifier}]; + + NSString* responseText = [response isKindOfClass:[UNTextInputNotificationResponse class]] ? ((UNTextInputNotificationResponse *)response).userText : nil; + if (responseText) { + [responseAction setObject:responseText forKey:@"text"]; + } + + return responseAction; +} + +@end diff --git a/RNNotifications/RNNotifications.h b/RNNotifications/RNNotifications.h index 1945ade..c470456 100644 --- a/RNNotifications/RNNotifications.h +++ b/RNNotifications/RNNotifications.h @@ -9,9 +9,12 @@ + (instancetype)sharedInstance; - (void)initialize; +- (void)initializePushKit; + - (void)didRegisterForRemoteNotificationsWithDeviceToken:(id)deviceToken; - (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; -- (void)finishHandleNotificationKey:(NSString *)notificationKey; +- (void)finishHandleNotificationKey:(NSString *)notificationKey presentingOptions:(UNNotificationPresentationOptions)presentingOptions; +- (void)finishHandleActionKey:(NSString *)actionKey; //- (void)setBadgeForNotification:(NSDictionary *)notification; diff --git a/RNNotifications/RNNotifications.m b/RNNotifications/RNNotifications.m index 90e76ae..35e5b42 100644 --- a/RNNotifications/RNNotifications.m +++ b/RNNotifications/RNNotifications.m @@ -4,10 +4,13 @@ #import #import "RNNotifications.h" #import "RNNotificationCenterListener.h" +#import "RNPushKit.h" @implementation RNNotifications { + RNPushKit* _pushKit; RNNotificationCenterListener* _notificationCenterListener; RNNotificationEventHandler* _notificationEventHandler; + RNPushKitEventHandler* _pushKitEventHandler; RNEventEmitter* _eventEmitter; RNNotificationsStore* _store; } @@ -33,6 +36,11 @@ _notificationCenterListener = [[RNNotificationCenterListener alloc] initWithNotificationEventHandler:_notificationEventHandler]; } +- (void)initializePushKit { + _pushKitEventHandler = [RNPushKitEventHandler new]; + _pushKit = [[RNPushKit alloc] initWithEventHandler:_pushKitEventHandler]; +} + - (void)didRegisterForRemoteNotificationsWithDeviceToken:(id)deviceToken { [_notificationEventHandler didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; } @@ -51,8 +59,12 @@ [_store setInitialNotification:notification]; } -- (void)finishHandleNotificationKey:(NSString *)notificationKey { - [_store completeAction:notificationKey]; +- (void)finishHandleActionKey:(NSString *)actionKey { + [_store completeAction:actionKey]; +} + +- (void)finishHandleNotificationKey:(NSString *)notificationKey presentingOptions:(UNNotificationPresentationOptions)presentingOptions { + [_store completePresentation:notificationKey withPresentationOptions:presentingOptions]; } @end diff --git a/RNNotifications/RNNotifications.xcodeproj/project.pbxproj b/RNNotifications/RNNotifications.xcodeproj/project.pbxproj index 31e9b6b..78cb8a7 100644 --- a/RNNotifications/RNNotifications.xcodeproj/project.pbxproj +++ b/RNNotifications/RNNotifications.xcodeproj/project.pbxproj @@ -33,6 +33,10 @@ 50AD1FCB22D13ADB00E12362 /* RNPushKitEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 50AD1FC922D13ADB00E12362 /* RNPushKitEventHandler.m */; }; 50E49F0722D1E4E0007160C1 /* RNNotificationsStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 50E49F0522D1E4E0007160C1 /* RNNotificationsStore.h */; }; 50E49F0822D1E4E0007160C1 /* RNNotificationsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E49F0622D1E4E0007160C1 /* RNNotificationsStore.m */; }; + 50FED76622D3E06500DDD516 /* RNNotificationCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 50FED76422D3E06500DDD516 /* RNNotificationCenter.h */; }; + 50FED76722D3E06500DDD516 /* RNNotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FED76522D3E06500DDD516 /* RNNotificationCenter.m */; }; + 50FED76E22D3EBA800DDD516 /* RNNotificationParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 50FED76C22D3EBA800DDD516 /* RNNotificationParser.h */; }; + 50FED76F22D3EBA800DDD516 /* RNNotificationParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FED76D22D3EBA800DDD516 /* RNNotificationParser.m */; }; D8A2F7551CB57F1A002CC8F5 /* RNNotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = D8A2F7541CB57F1A002CC8F5 /* RNNotifications.m */; }; /* End PBXBuildFile section */ @@ -86,6 +90,10 @@ 50AD1FC922D13ADB00E12362 /* RNPushKitEventHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNPushKitEventHandler.m; sourceTree = ""; }; 50E49F0522D1E4E0007160C1 /* RNNotificationsStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNotificationsStore.h; sourceTree = ""; }; 50E49F0622D1E4E0007160C1 /* RNNotificationsStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNotificationsStore.m; sourceTree = ""; }; + 50FED76422D3E06500DDD516 /* RNNotificationCenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNotificationCenter.h; sourceTree = ""; }; + 50FED76522D3E06500DDD516 /* RNNotificationCenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNotificationCenter.m; sourceTree = ""; }; + 50FED76C22D3EBA800DDD516 /* RNNotificationParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNotificationParser.h; sourceTree = ""; }; + 50FED76D22D3EBA800DDD516 /* RNNotificationParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNotificationParser.m; sourceTree = ""; }; D8A2F7541CB57F1A002CC8F5 /* RNNotifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotifications.m; sourceTree = ""; }; D8A2F7561CB57F28002CC8F5 /* RNNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNotifications.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -129,12 +137,16 @@ 508CE81122D12F3C00357815 /* Notifications */ = { isa = PBXGroup; children = ( + 50FED76422D3E06500DDD516 /* RNNotificationCenter.h */, + 50FED76522D3E06500DDD516 /* RNNotificationCenter.m */, 50E49F0522D1E4E0007160C1 /* RNNotificationsStore.h */, 50E49F0622D1E4E0007160C1 /* RNNotificationsStore.m */, 508CE7D322D12CCA00357815 /* RNNotificationEventHandler.h */, 508CE7D422D12CCA00357815 /* RNNotificationEventHandler.m */, 508CE81522D12FF500357815 /* RNNotificationCenterListener.h */, 508CE81322D12FC600357815 /* RNNotificationCenterListener.m */, + 50FED76C22D3EBA800DDD516 /* RNNotificationParser.h */, + 50FED76D22D3EBA800DDD516 /* RNNotificationParser.m */, ); name = Notifications; sourceTree = ""; @@ -202,10 +214,12 @@ 50AD1FCA22D13ADB00E12362 /* RNPushKitEventHandler.h in Headers */, 507DCCF922CE3F04005D4E0B /* RNNotifications.h in Headers */, 508CE7D522D12CCA00357815 /* RNNotificationEventHandler.h in Headers */, + 50FED76622D3E06500DDD516 /* RNNotificationCenter.h in Headers */, 508CE81922D130B900357815 /* RNPushKitEventListener.h in Headers */, 50E49F0722D1E4E0007160C1 /* RNNotificationsStore.h in Headers */, 508CE81622D12FF600357815 /* RNNotificationCenterListener.h in Headers */, 508CE82222D1372E00357815 /* RNUtils.h in Headers */, + 50FED76E22D3EBA800DDD516 /* RNNotificationParser.h in Headers */, 507DCCFA22CE3F04005D4E0B /* RNEventEmitter.h in Headers */, 507DCCFB22CE3F04005D4E0B /* RNCommandsHandler.h in Headers */, 507DCCFC22CE3F04005D4E0B /* RCTConvert+Notifications.h in Headers */, @@ -316,6 +330,8 @@ 50351F8F22CD782F000713B3 /* RNEventEmitter.m in Sources */, 508CE81A22D130B900357815 /* RNPushKitEventListener.m in Sources */, 50351F9222CD7DF4000713B3 /* RNBridgeModule.m in Sources */, + 50FED76722D3E06500DDD516 /* RNNotificationCenter.m in Sources */, + 50FED76F22D3EBA800DDD516 /* RNNotificationParser.m in Sources */, 508CE81E22D1337200357815 /* RNPushKit.m in Sources */, 508CE7D622D12CCA00357815 /* RNNotificationEventHandler.m in Sources */, 50E49F0822D1E4E0007160C1 /* RNNotificationsStore.m in Sources */, diff --git a/RNNotifications/RNNotificationsStore.h b/RNNotifications/RNNotificationsStore.h index 9babe03..56dcd0c 100644 --- a/RNNotifications/RNNotificationsStore.h +++ b/RNNotifications/RNNotificationsStore.h @@ -1,10 +1,14 @@ #import +@import UserNotifications; @interface RNNotificationsStore : NSObject @property NSDictionary* initialNotification; - (void)completeAction:(NSString *)completionKey; -- (void)setCompletionHandler:(void (^)())completionHandler withCompletionKey:(NSString *)completionKey; +- (void)completePresentation:(NSString *)completionKey withPresentationOptions:(UNNotificationPresentationOptions)presentationOptions; +- (void)setActionCompletionHandler:(void (^)())completionHandler withCompletionKey:(NSString *)completionKey; +- (void)setPresentationCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler withCompletionKey:(NSString *)completionKey; + @end diff --git a/RNNotifications/RNNotificationsStore.m b/RNNotifications/RNNotificationsStore.m index e7f8792..4b23543 100644 --- a/RNNotifications/RNNotificationsStore.m +++ b/RNNotifications/RNNotificationsStore.m @@ -2,18 +2,24 @@ @implementation RNNotificationsStore { NSMutableDictionary* _actionCompletionHandlers; + NSMutableDictionary* _presentationCompletionHandlers; } - (instancetype)init { self = [super init]; _actionCompletionHandlers = [NSMutableDictionary new]; + _presentationCompletionHandlers = [NSMutableDictionary new]; return self; } -- (void)setCompletionHandler:(void (^)())completionHandler withCompletionKey:(NSString *)completionKey { +- (void)setActionCompletionHandler:(void (^)())completionHandler withCompletionKey:(NSString *)completionKey { _actionCompletionHandlers[completionKey] = completionHandler; } +- (void)setPresentationCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler withCompletionKey:(NSString *)completionKey { + _presentationCompletionHandlers[completionKey] = completionHandler; +} + - (void)completeAction:(NSString *)completionKey { void (^completionHandler)() = (void (^)())[_actionCompletionHandlers valueForKey:completionKey]; if (completionHandler) { @@ -21,4 +27,13 @@ [_actionCompletionHandlers removeObjectForKey:completionKey]; } } + +- (void)completePresentation:(NSString *)completionKey withPresentationOptions:(UNNotificationPresentationOptions)presentationOptions { + void (^completionHandler)() = (void (^)(UNNotificationPresentationOptions))[_presentationCompletionHandlers valueForKey:completionKey]; + if (completionHandler) { + completionHandler(presentationOptions); + [_actionCompletionHandlers removeObjectForKey:completionKey]; + } +} + @end diff --git a/RNNotifications/RNPushKit.h b/RNNotifications/RNPushKit.h index 63e1669..3a0b22d 100644 --- a/RNNotifications/RNPushKit.h +++ b/RNNotifications/RNPushKit.h @@ -4,6 +4,6 @@ @interface RNPushKit : NSObject -- (instancetype)initWithPushKitEventListener:(RNPushKitEventListener *)pushKitEventListener; +- (instancetype)initWithEventHandler:(RNPushKitEventHandler *)pushKitEventHandler; @end diff --git a/RNNotifications/RNPushKit.m b/RNNotifications/RNPushKit.m index cc9a5bc..a0915a2 100644 --- a/RNNotifications/RNPushKit.m +++ b/RNNotifications/RNPushKit.m @@ -4,13 +4,13 @@ RNPushKitEventListener* _pushKitEventListener; } -- (instancetype)initWithPushKitEventListener:(RNPushKitEventListener *)pushKitEventListener { +- (instancetype)initWithEventHandler:(RNPushKitEventHandler *)pushKitEventHandler { self = [super init]; - _pushKitEventListener = pushKitEventListener; + _pushKitEventListener = [[RNPushKitEventListener alloc] initWithPushKitEventHandler:pushKitEventHandler]; PKPushRegistry* pushKitRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()]; - pushKitRegistry.delegate = pushKitEventListener; + pushKitRegistry.delegate = _pushKitEventListener; pushKitRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; return self; diff --git a/RNNotifications/RNPushKitEventListener.m b/RNNotifications/RNPushKitEventListener.m index 316ffaa..086fcd2 100644 --- a/RNNotifications/RNPushKitEventListener.m +++ b/RNNotifications/RNPushKitEventListener.m @@ -20,7 +20,7 @@ } - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type { - [_pushKitEventHandler didOpenNotificationPayload:payload.dictionaryPayload]; +// [_pushKitEventHandler didOpenNotificationPayload:payload.dictionaryPayload]; } @end diff --git a/docs/advancedIos.md b/docs/advancedIos.md index 9e44bde..ef272c2 100644 --- a/docs/advancedIos.md +++ b/docs/advancedIos.md @@ -182,7 +182,11 @@ import NotificationsIOS, { NotificationAction, NotificationCategory } from 'reac let upvoteAction = new NotificationAction({ activationMode: "background", title: String.fromCodePoint(0x1F44D), - identifier: "UPVOTE_ACTION" + identifier: "UPVOTE_ACTION", + textInput: { + buttonTitle: 'title', + placeholder: 'placeholder text' + } }, (action, completed) => { console.log("ACTION RECEIVED"); console.log(JSON.stringify(action)); diff --git a/example/index.ios.js b/example/index.ios.js index da2d5a7..f487aae 100644 --- a/example/index.ios.js +++ b/example/index.ios.js @@ -25,6 +25,10 @@ let replyAction = new NotificationAction({ title: 'Reply', behavior: 'textInput', authenticationRequired: true, + textInput: { + buttonTitle: 'Reply now', + placeholder: 'Insert message' + }, identifier: 'REPLY_ACTION' }, (action, completed) => { console.log('ACTION RECEIVED'); @@ -65,11 +69,13 @@ class NotificationsExampleApp extends Component { console.log('PushKit Token Received: ' + deviceToken); } - onNotificationReceivedForeground(notification) { + onNotificationReceivedForeground(notification, completion) { console.log('Notification Received Foreground: ' + JSON.stringify(notification)); this.setState({ notifications: [...this.state.notifications, notification] }); + + completion({}); } onNotificationOpened(notification) { diff --git a/example/ios/NotificationsExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/NotificationsExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json index 118c98f..19882d5 100644 --- a/example/ios/NotificationsExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/example/ios/NotificationsExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", @@ -29,6 +39,11 @@ "idiom" : "iphone", "size" : "60x60", "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/lib/src/index.ios.js b/lib/src/index.ios.js index aac7448..bc38d2b 100644 --- a/lib/src/index.ios.js +++ b/lib/src/index.ios.js @@ -81,7 +81,9 @@ export default class NotificationsIOS { } else { listener = DeviceEventEmitter.addListener( type, - notification => handler(new IOSNotification(notification)) + ({payload, identifier}) => handler(new IOSNotification(payload), (presentingOptions) => { + NativeRNNotifications.finishPresentingNotification(identifier, presentingOptions); + }) ); } @@ -111,7 +113,7 @@ export default class NotificationsIOS { action.notification = new IOSNotification(action.notification); actionHandler(action, () => { - NativeRNNotifications.completionHandler(action.completionKey); + NativeRNNotifications.finishHandlingAction(action.identifier); }); } } diff --git a/lib/src/notification.ios.js b/lib/src/notification.ios.js index 3d7be34..5f611ee 100644 --- a/lib/src/notification.ios.js +++ b/lib/src/notification.ios.js @@ -10,32 +10,32 @@ export default class IOSNotification { constructor(notification: Object) { this._data = {}; - if (notification.aps && - notification.aps['content-available'] && - notification.aps['content-available'] === 1 && - !notification.aps.alert && - !notification.aps.sound && + if (notification.userInfo.aps && + notification.userInfo.aps['content-available'] && + notification.userInfo.aps['content-available'] === 1 && + !notification.userInfo.aps.alert && + !notification.userInfo.aps.sound && notification.managedAps) { // managed notification this._alert = notification.managedAps.alert; this._sound = notification.managedAps.sound; - this._badge = notification.aps.badge; + this._badge = notification.userInfo.aps.badge; this._category = notification.managedAps.category; this._type = 'managed'; - this._thread = notification.aps['thread-id']; + this._thread = notification.userInfo.aps['thread-id']; } else if ( - notification.aps && - notification.aps.alert) { + notification.userInfo.aps && + notification.userInfo.aps.alert) { // regular notification - this._alert = notification.aps.alert; - this._sound = notification.aps.sound; - this._badge = notification.aps.badge; - this._category = notification.aps.category; + this._alert = notification.userInfo.aps.alert; + this._sound = notification.userInfo.aps.sound; + this._badge = notification.userInfo.aps.badge; + this._category = notification.category; this._type = 'regular'; - this._thread = notification.aps['thread-id']; + this._thread = notification.thread; } - Object.keys(notification).filter(key => key !== 'aps').forEach(key => { + Object.keys(notification).filter(key => key !== 'userInfo').forEach(key => { this._data[key] = notification[key]; }); } diff --git a/package.json b/package.json index a34d118..702a1fd 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "shell-utils": "1.x.x", "react-native": "0.60.0", "react": "16.8.6", - "detox": "12.x.x", + "detox": "13.x.x", "jest": "24.8.0", "metro-react-native-babel-preset": "0.55.x", "@babel/register": "7.4.4" -- 2.26.2