1// Copyright 2016-present 650 Industries. All rights reserved. 2 3#import <EXNotifications/EXLegacyRemoteNotificationPermissionRequester.h> 4#import <ExpoModulesCore/EXUtilities.h> 5 6@interface EXLegacyRemoteNotificationPermissionRequester () 7 8@property (nonatomic, strong) EXPromiseResolveBlock resolve; 9@property (nonatomic, strong) EXPromiseRejectBlock reject; 10@property (nonatomic, assign) BOOL remoteNotificationsRegistrationIsPending; 11@property (nonatomic, weak) id<EXPermissionsRequester> userNotificationPermissionRequester; 12@property (nonatomic, weak) dispatch_queue_t methodQueue; 13@property (nonatomic, weak) id<EXRemoteNotificationPermissionProgressPublisher> permissionProgressPublisher; 14 15@end 16 17@implementation EXLegacyRemoteNotificationPermissionRequester 18 19+ (NSString *)permissionType 20{ 21 return @"notifications"; 22} 23 24- (instancetype)initWithUserNotificationPermissionRequester:(id<EXPermissionsRequester>)userNotificationPermissionRequester 25 permissionPublisher:(id<EXRemoteNotificationPermissionProgressPublisher>)permissionProgressPublisher 26 withMethodQueue:(dispatch_queue_t)methodQueue 27{ 28 if (self = [super init]) { 29 _remoteNotificationsRegistrationIsPending = NO; 30 _permissionProgressPublisher = permissionProgressPublisher; 31 _userNotificationPermissionRequester = userNotificationPermissionRequester; 32 _methodQueue = methodQueue; 33 } 34 return self; 35} 36 37- (NSDictionary *)getPermissions 38{ 39 __block EXPermissionStatus status; 40 [EXUtilities performSynchronouslyOnMainThread:^{ 41 status = (UMSharedApplication().isRegisteredForRemoteNotifications) ? 42 EXPermissionStatusGranted : 43 EXPermissionStatusUndetermined; 44 }]; 45 NSMutableDictionary *permissions = [[_userNotificationPermissionRequester getPermissions] mutableCopy]; 46 47 [permissions setValuesForKeysWithDictionary:@{ 48 @"status": @(status), 49 50 }]; 51 return permissions; 52} 53 54- (void)requestPermissionsWithResolver:(EXPromiseResolveBlock)resolve rejecter:(EXPromiseRejectBlock)reject 55{ 56 if (_resolve != nil || _reject != nil) { 57 reject(@"E_AWAIT_PROMISE", @"Another request for the same permission is already being handled.", nil); 58 return; 59 } 60 61 _resolve = resolve; 62 _reject = reject; 63 64 BOOL __block isRegisteredForRemoteNotifications = NO; 65 [EXUtilities performSynchronouslyOnMainThread:^{ 66 isRegisteredForRemoteNotifications = UMSharedApplication().isRegisteredForRemoteNotifications; 67 }]; 68 69 if (isRegisteredForRemoteNotifications) { 70 // resolve immediately if already registered 71 [self _maybeConsumeResolverWithCurrentPermissions]; 72 } else { 73 [_permissionProgressPublisher addDelegate:self]; 74 EX_WEAKIFY(self) 75 [_userNotificationPermissionRequester requestPermissionsWithResolver:^(NSDictionary *permission){ 76 EX_STRONGIFY(self) 77 EXPermissionStatus localNotificationsStatus = [[permission objectForKey:@"status"] intValue]; 78 // We may assume that `EXLocalNotificationRequester`'s permission request will always finish 79 // when the user responds to the dialog or has already responded in the past. 80 // However, `UIApplication.registerForRemoteNotification` results in calling 81 // `application:didRegisterForRemoteNotificationsWithDeviceToken:` or 82 // `application:didFailToRegisterForRemoteNotificationsWithError:` on the application delegate 83 // ONLY when the notifications are enabled in settings (by allowing sound, alerts or app badge). 84 // So, when the local notifications are disabled, the application delegate's callbacks will not be called instantly. 85 if (localNotificationsStatus == EXPermissionStatusDenied) { 86 [self _clearObserver]; 87 [self _maybeConsumeResolverWithCurrentPermissions]; 88 } else { 89 self.remoteNotificationsRegistrationIsPending = YES; 90 dispatch_async(dispatch_get_main_queue(), ^{ 91 [UMSharedApplication() registerForRemoteNotifications]; 92 }); 93 } 94 } rejecter:^(NSString *code, NSString *message, NSError *error){ 95 [self _clearObserver]; 96 if (self.reject) { 97 self.reject(code, message, error); 98 } 99 }]; 100 } 101} 102 103- (void)dealloc 104{ 105 [self _clearObserver]; 106} 107 108- (void)handleDidFinishRegisteringForRemoteNotifications 109{ 110 [self _clearObserver]; 111 EX_WEAKIFY(self) 112 dispatch_async(_methodQueue, ^{ 113 EX_STRONGIFY(self) 114 [self _maybeConsumeResolverWithCurrentPermissions]; 115 }); 116} 117 118- (void)_clearObserver 119{ 120 [_permissionProgressPublisher removeDelegate:self]; 121 _remoteNotificationsRegistrationIsPending = NO; 122} 123 124- (void)_maybeConsumeResolverWithCurrentPermissions 125{ 126 if (!_remoteNotificationsRegistrationIsPending) { 127 if (_resolve) { 128 _resolve([self getPermissions]); 129 _resolve = nil; 130 _reject = nil; 131 } 132 } 133} 134 135@end 136