1// Copyright 2018-present 650 Industries. All rights reserved. 2 3#import <EXNotifications/EXSingleNotificationHandlerTask.h> 4#import <EXNotifications/EXNotificationSerializer.h> 5 6static NSString * const onHandleNotification = @"onHandleNotification"; 7static NSString * const onHandleNotificationTimeout = @"onHandleNotificationTimeout"; 8 9static NSString * const shouldShowAlertKey = @"shouldShowAlert"; 10static NSString * const shouldPlaySoundKey = @"shouldPlaySound"; 11static NSString * const shouldSetBadgeKey = @"shouldSetBadge"; 12 13static NSTimeInterval const secondsToTimeout = 3; 14 15static NSString * const EXNotificationHandlerErrorDomain = @"expo.notifications.handler"; 16 17@interface EXSingleNotificationHandlerTask () 18 19@property (nonatomic, weak) id<EXEventEmitterService> eventEmitter; 20@property (nonatomic, strong) UNNotification *notification; 21@property (nonatomic, copy) void (^completionHandler)(UNNotificationPresentationOptions); 22 23@property (nonatomic, weak) id<EXSingleNotificationHandlerTaskDelegate> delegate; 24 25@property (nonatomic, strong) NSTimer *timer; 26 27@end 28 29@implementation EXSingleNotificationHandlerTask 30 31+ (NSArray<NSString *> *)eventNames 32{ 33 return @[onHandleNotification, onHandleNotificationTimeout]; 34} 35 36- (instancetype)initWithEventEmitter:(id<EXEventEmitterService>)eventEmitter 37 notification:(UNNotification *)notification 38 completionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler 39 delegate:(nonnull id<EXSingleNotificationHandlerTaskDelegate>)delegate 40{ 41 if (self = [super init]) { 42 _eventEmitter = eventEmitter; 43 _notification = notification; 44 _completionHandler = completionHandler; 45 _delegate = delegate; 46 } 47 return self; 48} 49 50- (NSString *)identifier 51{ 52 return _notification.request.identifier; 53} 54 55- (void)start 56{ 57 [_eventEmitter sendEventWithName:onHandleNotification body:@{ 58 @"id": _notification.request.identifier, 59 @"notification": [EXNotificationSerializer serializedNotification:_notification] 60 }]; 61 _timer = [NSTimer scheduledTimerWithTimeInterval:secondsToTimeout target:self selector:@selector(handleTimeout) userInfo:nil repeats:NO]; 62} 63 64- (nullable NSError *)handleResponse:(NSDictionary *)response 65{ 66 @synchronized (self) { 67 NSError *maybeError = [self callCompletionHandlerWithOptions:[self presentationOptionsFromResponse:response]]; 68 [self finish]; 69 return maybeError; 70 } 71} 72 73- (void)handleTimeout 74{ 75 @synchronized (self) { 76 [_eventEmitter sendEventWithName:onHandleNotificationTimeout body:@{ 77 @"id": _notification.request.identifier, 78 @"notification": [EXNotificationSerializer serializedNotification:_notification] 79 }]; 80 [self callCompletionHandlerWithOptions:UNNotificationPresentationOptionNone]; 81 [self finish]; 82 } 83} 84 85- (nullable NSError *)callCompletionHandlerWithOptions:(UNNotificationPresentationOptions)options 86{ 87 if (_completionHandler) { 88 _completionHandler(options); 89 _completionHandler = nil; 90 return nil; 91 } else { 92 return [NSError errorWithDomain:EXNotificationHandlerErrorDomain code:-1 userInfo:@{ 93 @"code": @"ERR_NOTIFICATION_RESPONSE_TIMEOUT", 94 @"message": @"Notification has already been handled. Most probably the request has timed out." 95 }]; 96 } 97} 98 99- (void)finish 100{ 101 [_timer invalidate]; 102 _timer = nil; 103 [_delegate taskDidFinish:self]; 104} 105 106- (UNNotificationPresentationOptions)presentationOptionsFromResponse:(NSDictionary *)response 107{ 108 UNNotificationPresentationOptions options = UNNotificationPresentationOptionNone; 109 110 // TODO(iOS 14): use UNNotificationPresentationOptionList and UNNotificationPresentationOptionBanner 111 if ([response[shouldShowAlertKey] boolValue]) { 112 options |= UNNotificationPresentationOptionAlert; 113 } 114 if ([response[shouldPlaySoundKey] boolValue]) { 115 options |= UNNotificationPresentationOptionSound; 116 } 117 if ([response[shouldSetBadgeKey] boolValue]) { 118 options |= UNNotificationPresentationOptionBadge; 119 } 120 121 return options; 122} 123 124@end 125