diff --git a/RNNotifications/RCTConvert+Notifications.h b/RNNotifications/RCTConvert+Notifications.h index aaff9dc987ecf9e008d4fdc244a1319969ae7f7c..519ce17c0b51c8c631d45de4e1a40bfc7cf211d9 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 2a330e1669d77a0f9d30e562a449e5011320eb19..431cc4e74752e8c6d953267d5bb4abc438fcedc1 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 9850b49ec92cf8716ff7e9afd9e3032ea653295e..9d43e6679a7f5c74df8674799d4126c9df2d656b 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 1ce85e90f25830a347fdcf04226c0441d0fb6a4f..244726803494ce4f4408d0f297b11de21bab492a 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 f2b95380d808a05c3482a3bda24044da3e799d6f..d5fca1164a9f5144a7a8b2834e24df69a52ba518 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 33e8db75df7c1483536459364a86670de67abb38..e2008e2558e43081a62dcdf74e9fe1bce6d91c5f 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 695bca03413a10c3969a7b98557de908eadcc856..f8c9edc0ca7f90228cc6812bfdd3fbad2b361a2c 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 0000000000000000000000000000000000000000..b5da6a3cc88c818cabad96b19698ae7333737f1a --- /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 0000000000000000000000000000000000000000..803ba56e7d819c826a8d50d587fb83440ac07227 --- /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 487c8733ab17014a74af4bfd468ee3cb40e169ca..3df99a2db39ce8f7bf0eabfdbe7965caf871473d 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 7b6cc0e7c254b74485a249d439e262621dbe7cad..413e0cd4afdbf3eb18fd9dbd73af5211793c391f 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 48f03c269f84b6c27d7d98eb4575035841e1306b..1fc1b21f5ba9c1f59e43de5cdb81a2efc772d3a5 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 0000000000000000000000000000000000000000..6397d20ce71834ab6041eafaf7180f2e0fb2e0b9 --- /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 0000000000000000000000000000000000000000..aee4cadbf41d55faeab66a3f6a16eab5ef0d97de --- /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 1945adeed65169398d4c44cb2b61a7eb33107605..c470456cbcc20f61ceaaf13d10fd47a226d7d6e3 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 90e76aef713ec9d1f5a63808df5f25ec0157d99c..35e5b4237e2e7527507dbc72264ebf980b9bdbb2 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 31e9b6b6460aa998a0bdb5716642d0cbbceba11f..78cb8a78a3ca2a4b799e6efa40757f0df6d8049d 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 9babe03889067eac72177fb81fd9d87e84db577f..56dcd0ced02ceaef70bdfdb91e83543cef95de69 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 e7f879279b23c005b12b7a9aa97be32f30c383ea..4b235435ed8ba3236743ae9990cefe252cf5acd9 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 63e1669a7512bc65f1c0c91c66c1d4ec9ec7688b..3a0b22d419a5a6dff75cb396135d975f1118baff 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 cc9a5bc66fe0a1100fdf5b46dd95b0a38e4b5f77..a0915a2ee6470379dd73c6cb06c06e96e8a5210e 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 316ffaa4cdf7733489612d29d9e663ab28c88f82..086fcd2f9f135c59514d3093474f629fbb940e8f 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 9e44bde671158c2b25eea0a66aa3a593d7d2cdca..ef272c20c9a2641a240d2af4ea1bc6fad9d205e4 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 da2d5a713cdc9ab9fe5b3749a220241661a01e8f..f487aae6f0e4a3c20d670c522420d12cad2cc02d 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 118c98f7461bf98b2bc7e061150d8021121ad277..19882d568afa3dc606f10cc14b661c17c824d11c 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 aac7448f887ae2ef91847ed4e94d9ecc8c33d8f0..bc38d2bd3bb7f4f9f14383c1c6d7f94cbc979ead 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 3d7be34280b7948926a22bd10609ba5fb431b458..5f611eeaca5d42466eefc0b90c3368f7e206409e 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 a34d11837d68f76aa05bab62e4f194f1f75ba9c2..702a1fd8726a66bb9dcc811e3022efe778e42fad 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"