1// Copyright 2018-present 650 Industries. All rights reserved. 2 3#import <EXNotifications/EXNotificationPresentationModule.h> 4 5#import <EXNotifications/EXNotificationBuilder.h> 6#import <EXNotifications/EXNotificationSerializer.h> 7#import <EXNotifications/EXNotificationCenterDelegate.h> 8 9@interface EXNotificationPresentationModule () 10 11@property (nonatomic, weak) id<EXNotificationBuilder> notificationBuilder; 12 13// Remove once presentNotificationAsync is removed 14@property (nonatomic, strong) NSCountedSet<NSString *> *presentedNotifications; 15@property (nonatomic, weak) id<EXNotificationCenterDelegate> notificationCenterDelegate; 16 17@end 18 19@implementation EXNotificationPresentationModule 20 21EX_EXPORT_MODULE(ExpoNotificationPresenter); 22 23// Remove once presentNotificationAsync is removed 24- (instancetype)init 25{ 26 if (self = [super init]) { 27 _presentedNotifications = [NSCountedSet set]; 28 } 29 return self; 30} 31 32# pragma mark - Exported methods 33 34// Remove once presentNotificationAsync is removed 35EX_EXPORT_METHOD_AS(presentNotificationAsync, 36 presentNotificationWithIdentifier:(NSString *)identifier 37 notification:(NSDictionary *)notificationSpec 38 resolve:(EXPromiseResolveBlock)resolve 39 reject:(EXPromiseRejectBlock)reject) 40{ 41 UNNotificationContent *content = [_notificationBuilder notificationContentFromRequest:notificationSpec]; 42 UNNotificationTrigger *trigger = nil; 43 UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger]; 44 [_presentedNotifications addObject:identifier]; 45 __weak EXNotificationPresentationModule *weakSelf = self; 46 [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { 47 if (error) { 48 // If there was no error, willPresentNotification: callback will remove the identifier from the set 49 [weakSelf.presentedNotifications removeObject:identifier]; 50 NSString *message = [NSString stringWithFormat:@"Notification could not have been presented: %@", error.description]; 51 reject(@"ERR_NOTIF_PRESENT", message, error); 52 } else { 53 resolve(identifier); 54 } 55 }]; 56} 57 58EX_EXPORT_METHOD_AS(getPresentedNotificationsAsync, 59 getPresentedNotificationsAsyncWithResolve:(EXPromiseResolveBlock)resolve 60 reject:(EXPromiseRejectBlock)reject) 61{ 62 [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) { 63 resolve([self serializeNotifications:notifications]); 64 }]; 65} 66 67 68EX_EXPORT_METHOD_AS(dismissNotificationAsync, 69 dismissNotificationWithIdentifier:(NSString *)identifier 70 resolve:(EXPromiseResolveBlock)resolve 71 reject:(EXPromiseRejectBlock)reject) 72{ 73 [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[identifier]]; 74 resolve(nil); 75} 76 77EX_EXPORT_METHOD_AS(dismissAllNotificationsAsync, 78 dismissAllNotificationsWithResolver:(EXPromiseResolveBlock)resolve 79 reject:(EXPromiseRejectBlock)reject) 80{ 81 [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications]; 82 resolve(nil); 83} 84 85# pragma mark - EXModuleRegistryConsumer 86 87- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry 88{ 89 _notificationBuilder = [moduleRegistry getModuleImplementingProtocol:@protocol(EXNotificationBuilder)]; 90 91 // Remove once presentNotificationAsync is removed 92 id<EXNotificationCenterDelegate> notificationCenterDelegate = (id<EXNotificationCenterDelegate>)[moduleRegistry getSingletonModuleForName:@"NotificationCenterDelegate"]; 93 [notificationCenterDelegate addDelegate:self]; 94} 95 96// Remove once presentNotificationAsync is removed 97# pragma mark - EXNotificationsDelegate 98 99- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler 100{ 101 UNNotificationPresentationOptions presentationOptions = UNNotificationPresentationOptionNone; 102 103 NSString *identifier = notification.request.identifier; 104 if ([_presentedNotifications containsObject:identifier]) { 105 [_presentedNotifications removeObject:identifier]; 106 // TODO(iOS 14): use UNNotificationPresentationOptionList and UNNotificationPresentationOptionBanner 107 presentationOptions = UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge; 108 } 109 110 completionHandler(presentationOptions); 111} 112 113# pragma mark - Helpers 114 115- (NSArray * _Nonnull)serializeNotifications:(NSArray<UNNotification *> * _Nonnull)notifications 116{ 117 NSMutableArray *serializedNotifications = [NSMutableArray new]; 118 for (UNNotification *notification in notifications) { 119 [serializedNotifications addObject:[EXNotificationSerializer serializedNotification:notification]]; 120 } 121 return serializedNotifications; 122} 123 124@end 125