RNNotifications.m 26 KB
Newer Older
Lidan Hifi's avatar
Lidan Hifi committed
1 2

#import <UIKit/UIKit.h>
3 4 5 6 7
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import "RNNotifications.h"
#import <React/RCTConvert.h>
#import <React/RCTUtils.h>
8
#import "RNNotificationsBridgeQueue.h"
9
#import <UserNotifications/UserNotifications.h>
Lidan Hifi's avatar
Lidan Hifi committed
10

11 12
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

13 14
NSString* const RNNotificationCreateAction = @"CREATE";
NSString* const RNNotificationClearAction = @"CLEAR";
Lidan Hifi's avatar
Lidan Hifi committed
15

16 17 18 19 20 21
NSString* const RNNotificationsRegistered = @"remoteNotificationsRegistered";
NSString* const RNNotificationsRegistrationFailed = @"remoteNotificationsRegistrationFailed";
NSString* const RNPushKitRegistered = @"pushKitRegistered";
NSString* const RNNotificationReceivedForeground = @"notificationReceivedForeground";
NSString* const RNNotificationReceivedBackground = @"notificationReceivedBackground";
NSString* const RNNotificationOpened = @"notificationOpened";
22
NSString* const RNNotificationActionTriggered = @"RNNotificationActionTriggered";
23 24
NSString* const RNNotificationActionReceived = @"notificationActionReceived";
//NSString* const RNNotificationActionDismissed = @"RNNotificationActionDismissed";
Lidan Hifi's avatar
Lidan Hifi committed
25

26

27 28 29
////////////////////////////////////////////////////////////////
#pragma mark conversions
////////////////////////////////////////////////////////////////
30 31

@implementation RCTConvert (UIUserNotificationActionBehavior)
32 33 34 35 36
RCT_ENUM_CONVERTER(UNNotificationActionOptions, (@{
                                                   @"authRequired": @(UNNotificationActionOptionAuthenticationRequired),
                                                   @"textInput": @(UNNotificationActionOptionDestructive),
                                                   @"foreGround": @(UNNotificationActionOptionForeground)
                                                   }), UNNotificationActionOptionAuthenticationRequired, integerValue)
37 38
@end

39 40 41 42 43 44 45 46
@implementation RCTConvert (UNNotificationCategoryOptions)
RCT_ENUM_CONVERTER(UNNotificationCategoryOptions, (@{
                                                     @"none": @(UNNotificationCategoryOptionNone),
                                                     @"customDismiss": @(UNNotificationCategoryOptionCustomDismissAction),
                                                     @"allowInCarPlay": @(UNNotificationCategoryOptionAllowInCarPlay),
                                                     //                                                     @"hiddenPreviewsShowTitle": @(UNNotificationCategoryOptionHiddenPreviewsShowTitle),
                                                     //                                                     @"hiddenPreviewsShowSubtitle": @(UNNotificationCategoryOptionHiddenPreviewsShowSubtitle)
                                                     }), UNNotificationCategoryOptionNone, integerValue)
47
@end
48

49 50 51



52 53
@implementation RCTConvert (UNNotificationAction)
+ (UNNotificationAction*) UNNotificationAction:(id)json
54 55
{
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
56 57 58 59 60
    UNNotificationAction* action = [UNNotificationAction actionWithIdentifier:details[@"identifier"]
                                                                        title:details[@"title"]
                                                                      options:[RCTConvert UNNotificationActionOptions:details[@"options"]]];
    
    return action;
61 62 63
}
@end

64 65 66 67
@implementation RCTConvert (UNNotificationRequest)
+ (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSString*)notificationId
{
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
68
    
69 70 71
    UNMutableNotificationContent *content = [UNMutableNotificationContent new];
    content.body = [RCTConvert NSString:details[@"alertBody"]];
    content.title = [RCTConvert NSString:details[@"alertTitle"]];
72 73 74
    content.sound = [RCTConvert NSString:details[@"soundName"]] ? [UNNotificationSound soundNamed:[RCTConvert NSString:details[@"soundName"]]] : [UNNotificationSound defaultSound];
    if ([RCTConvert BOOL:details[@"silent"]])
    {
75 76
        content.sound = nil;
    }
77 78
    content.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]] ?: @{};
    content.categoryIdentifier = [RCTConvert NSString:details[@"category"]];
79
    
80 81
    NSDate *triggerDate = [RCTConvert NSDate:details[@"fireDate"]];
    UNCalendarNotificationTrigger *trigger = nil;
82 83
    NSLog(@"ABOELBISHER : the fire date is %@", triggerDate);
    
84 85 86 87 88 89 90 91 92 93
    if (triggerDate != nil) {
        NSDateComponents *triggerDateComponents = [[NSCalendar currentCalendar]
                                                   components:NSCalendarUnitYear +
                                                   NSCalendarUnitMonth + NSCalendarUnitDay +
                                                   NSCalendarUnitHour + NSCalendarUnitMinute +
                                                   NSCalendarUnitSecond + NSCalendarUnitTimeZone
                                                   fromDate:triggerDate];
        trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDateComponents
                                                                           repeats:NO];
    }
94
    
95 96 97 98 99
    return [UNNotificationRequest requestWithIdentifier:notificationId
                                                content:content trigger:trigger];
}
@end

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

@implementation RCTConvert (UNNotificationCategory)
+ (UNNotificationCategory*) UNNotificationCategory:(id)json
{
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
    NSString* identefier = [RCTConvert NSString:details[@"identifier"]];
    
    NSMutableArray* actions = [NSMutableArray new];
    for (NSDictionary* actionJson in [RCTConvert NSArray:details[@"actions"]])
    {
        [actions addObject:[RCTConvert UNNotificationAction:actionJson]];
    }
    
    NSMutableArray* intentIdentifiers = [NSMutableArray new];
    for(NSDictionary* intentJson in [RCTConvert NSArray:details[@"intentIdentifiers"]])
    {
        [intentIdentifiers addObject:[RCTConvert NSString:intentJson]];
    }
    
    UNNotificationCategory* cat =  [UNNotificationCategory categoryWithIdentifier:identefier
                                                                          actions:actions
                                                                intentIdentifiers:intentIdentifiers
                                                                          options:[RCTConvert UNNotificationCategoryOptions:details[@"options"]]];
    return cat;
}
@end

127 128
static NSDictionary *RCTFormatUNNotification(UNNotification *notification)
{
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    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;
}
149

150

151 152
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
153

154
@interface RNNotifications()
155

156 157
@property(nonatomic) bool hasListeners;
@property(nonatomic) NSDictionary* openedNotification;
158

159
@end
160

161
@implementation RNNotifications
162 163
RCT_EXPORT_MODULE()

164
- (instancetype)init
Lidan Hifi's avatar
Lidan Hifi committed
165
{
166 167 168 169 170 171 172
    NSLog(@"ABOELBISHER : init");
    self = [super init];
    {
        _hasListeners = NO;
        [RNNRouter sharedInstance].delegate = self;
    }
    return self;
Lidan Hifi's avatar
Lidan Hifi committed
173 174
}

Artal Druk's avatar
Artal Druk committed
175 176 177
+ (BOOL)requiresMainQueueSetup {
    return YES;
}
178

Lidan Hifi's avatar
Lidan Hifi committed
179 180
- (void)setBridge:(RCTBridge *)bridge
{
181 182 183 184 185 186 187 188
    NSLog(@"ABOELBISHER : bridge set");
    [super setBridge:bridge];
    _openedNotification = [bridge.launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification = [bridge.launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    //    UILocalNotification *localNotification = [bridge.launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    //    [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification = localNotification ? localNotification.userInfo : nil;
    
}
Lidan Hifi's avatar
Lidan Hifi committed
189

190 191 192
////////////////////////////////////////////////////////////////
#pragma mark private functions
////////////////////////////////////////////////////////////////
193

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
+ (void)requestPermissionsWithCategories:(NSMutableSet *)categories
{
    dispatch_async(dispatch_get_main_queue(), ^{
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
            if(!error)
            {
                if (granted)
                {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categories];
                        [[UIApplication sharedApplication] registerForRemoteNotifications];
                    });
                }
            }
        }];
    });
}

////////////////////////////////////////////////////////////////
#pragma mark NRNNManagerDelegate
////////////////////////////////////////////////////////////////
//application:didReceiveLocalNotification : replacement

//called when a notification is delivered to a foreground ap
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
    dispatch_async(dispatch_get_main_queue(), ^{
        
        //        //TODO: check WTF is this
        //        NSMutableDictionary* newUserInfo = notification.request.content.userInfo.mutableCopy;
        //        [newUserInfo removeObjectForKey:@"__id"];
        //        notification.request.content.userInfo = newUserInfo;
        //        ////
        
        if (![RNNotificationsBridgeQueue sharedInstance].jsIsReady)
        {
            [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification = notification.request.content.userInfo;
            return;
        }
        
        NSLog(@"ABOELBISHER : willPresentNotification");
        UIApplicationState state = [UIApplication sharedApplication].applicationState;
        [self handleReceiveNotification:state userInfo:notification.request.content.userInfo];
        completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
    });
}
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
//called when a user selects an action in a delivered notification
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
{
    NSString* identifier = response.actionIdentifier;
    NSString* completionKey = [NSString stringWithFormat:@"%@.%@", identifier, [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]]];
    NSMutableDictionary* info = [[NSMutableDictionary alloc] initWithDictionary:@{ @"identifier": identifier, @"completionKey": completionKey }];
    
    // add text
    NSString* text = ((UNTextInputNotificationResponse*)response).userText;//[response objectForKey:UIUserNotificationActionResponseTypedTextKey];
    if (text != NULL) {
        info[@"text"] = text;
    }
    
    NSDictionary* userInfo = response.notification.request.content.userInfo;
    
    // add notification custom data
    if (userInfo != NULL) {
        info[@"notification"] = userInfo;
    }
    
    // Emit event to the queue (in order to store the completion handler). if JS thread is ready, post it also to the notification center (to the bridge).
    [[RNNotificationsBridgeQueue sharedInstance] postAction:info withCompletionKey:completionKey andCompletionHandler:completionHandler];
    
    if ([RNNotificationsBridgeQueue sharedInstance].jsIsReady == YES) {
        [self checkAndSendEvent:RNNotificationActionTriggered body:info];
        completionHandler();
    } else {
        [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification = info;
    }
    
}
273

274 275 276 277 278
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString * str = [RNNotifications deviceTokenToString:deviceToken];
    [self checkAndSendEvent:RNNotificationsRegistered body:@{@"deviceToken":str}];
}
Lidan Hifi's avatar
Lidan Hifi committed
279

280 281 282 283 284
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    [self checkAndSendEvent:RNNotificationsRegistrationFailed
                       body:@{@"code": [NSNumber numberWithInteger:error.code], @"domain": error.domain, @"localizedDescription": error.localizedDescription}];
}
Lidan Hifi's avatar
Lidan Hifi committed
285

286 287 288 289 290 291 292 293 294 295 296 297
//the system calls this method when your app is running in the foreground or background
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    if ([RNNotificationsBridgeQueue sharedInstance].jsIsReady) {
        dispatch_async(dispatch_get_main_queue(), ^{
            UIApplicationState state = [UIApplication sharedApplication].applicationState;
            [self handleReceiveNotification:state userInfo:userInfo];
        });
    } else {
        [[RNNotificationsBridgeQueue sharedInstance] postNotification:userInfo];
    }
}
298

299 300 301 302 303 304 305 306 307 308 309 310 311 312
-(void) handleReceiveNotification:(UIApplicationState)state userInfo:(NSDictionary*)userInfo
{
    switch ((int)state)
    {
        case (int)UIApplicationStateActive:
            [self checkAndSendEvent:RNNotificationReceivedForeground body:userInfo];
            
        case (int)UIApplicationStateInactive:
            [self checkAndSendEvent:RNNotificationOpened body:userInfo];
            
        default:
            [self checkAndSendEvent:RNNotificationReceivedBackground body:userInfo];
    }
}
313

314 315 316
- (void)handlePushKitRegistered:(NSDictionary *)notification
{
    [self checkAndSendEvent:RNPushKitRegistered body:notification];
Lidan Hifi's avatar
Lidan Hifi committed
317 318
}

319 320 321 322 323
////////////////////////////////////////////////////////////////
#pragma mark ecents emitter side
////////////////////////////////////////////////////////////////

- (NSArray<NSString *> *)supportedEvents
324
{
325 326 327 328 329 330 331
    
    return @[ RNNotificationsRegistered,
              RNNotificationsRegistrationFailed,
              RNNotificationReceivedForeground,
              RNNotificationReceivedBackground,
              RNNotificationOpened];
    
332 333
}

334
-(void) checkAndSendEvent:(NSString*)name body:(id)body
335
{
336 337 338 339
    if(_hasListeners)
    {
        [self sendEventWithName:name body:body];
    }
340 341
}

342 343 344
- (void)stopObserving
{
    _hasListeners = NO;
345 346
}

347
- (void)startObserving
Lidan Hifi's avatar
Lidan Hifi committed
348
{
349 350
    _hasListeners = YES;
}
Lidan Hifi's avatar
Lidan Hifi committed
351

352 353 354 355 356 357 358 359 360 361 362 363 364
////////////////////////////////////////////////////////////////
#pragma mark exported method
////////////////////////////////////////////////////////////////

RCT_EXPORT_METHOD(requestPermissionsWithCategories:(NSArray *)json)
{
    NSMutableSet* categories = nil;
    if ([json count] > 0)
    {
        categories = [NSMutableSet new];
        for (NSDictionary* dic in json)
        {
            [categories addObject:[RCTConvert UNNotificationCategory:dic]];
365
        }
Lidan Hifi's avatar
Lidan Hifi committed
366
    }
367
    [RNNotifications requestPermissionsWithCategories:categories];
Lidan Hifi's avatar
Lidan Hifi committed
368 369
}

370
RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification withId:(NSString *)notificationId)
Lidan Hifi's avatar
Lidan Hifi committed
371
{
372 373 374
    UNNotificationRequest* localNotification = [RCTConvert UNNotificationRequest:notification withId:notificationId];
    [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotification withCompletionHandler:nil];
}
Lidan Hifi's avatar
Lidan Hifi committed
375

376 377 378 379 380
RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId)
{
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center removePendingNotificationRequestsWithIdentifiers:@[notificationId]];
}
381

382 383 384
RCT_EXPORT_METHOD(abandonPermissions)
{
    [[UIApplication sharedApplication] unregisterForRemoteNotifications];
Lidan Hifi's avatar
Lidan Hifi committed
385 386
}

387
RCT_EXPORT_METHOD(getBadgesCount:(RCTResponseSenderBlock)callback)
388
{
389 390
    NSInteger count = [UIApplication sharedApplication].applicationIconBadgeNumber;
    callback(@[ [NSNumber numberWithInteger:count] ]);
391 392
}

393
RCT_EXPORT_METHOD(setBadgesCount:(int)count)
394
{
395
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:count];
396 397
}

Lidan Hifi's avatar
Lidan Hifi committed
398 399 400
/*
 * Notification handlers
 */
401 402 403 404 405 406
//+ (void)didReceiveNotificationOnForegroundState:(NSDictionary *)notification
//{
//    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationReceivedForeground
//                                                        object:self
//                                                      userInfo:notification];
//}
Lidan Hifi's avatar
Lidan Hifi committed
407

408
-(void)didReceiveNotificationOnBackgroundState:(NSDictionary *)notification
Lidan Hifi's avatar
Lidan Hifi committed
409
{
410 411 412 413
    NSDictionary* managedAps  = [notification objectForKey:@"managedAps"];
    NSDictionary* alert = [managedAps objectForKey:@"alert"];
    NSString* action = [managedAps objectForKey:@"action"];
    NSString* notificationId = [managedAps objectForKey:@"notificationId"];
414
    
Lidan Hifi's avatar
Lidan Hifi committed
415 416
    if (action) {
        // create or delete notification
Lidan Hifi's avatar
Lidan Hifi committed
417
        if ([action isEqualToString: RNNotificationCreateAction]
Lidan Hifi's avatar
Lidan Hifi committed
418 419 420
            && notificationId
            && alert) {
            [self dispatchLocalNotificationFromNotification:notification];
421
            
Lidan Hifi's avatar
Lidan Hifi committed
422
        } else if ([action isEqualToString: RNNotificationClearAction] && notificationId) {
Lidan Hifi's avatar
Lidan Hifi committed
423 424 425
            [self clearNotificationFromNotificationsCenter:notificationId];
        }
    }
426 427 428
    
    [self checkAndSendEvent:RNNotificationReceivedBackground body:notification];
    
Lidan Hifi's avatar
Lidan Hifi committed
429 430 431 432
}

+ (void)didNotificationOpen:(NSDictionary *)notification
{
Lidan Hifi's avatar
Lidan Hifi committed
433
    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationOpened
Lidan Hifi's avatar
Lidan Hifi committed
434 435 436 437 438 439 440
                                                        object:self
                                                      userInfo:notification];
}

/*
 * Helper methods
 */
441
-(void)dispatchLocalNotificationFromNotification:(NSDictionary *)notification
Lidan Hifi's avatar
Lidan Hifi committed
442
{
443 444 445 446
    NSDictionary* managedAps  = [notification objectForKey:@"managedAps"];
    NSDictionary* alert = [managedAps objectForKey:@"alert"];
    NSString* action = [managedAps objectForKey:@"action"];
    NSString* notificationId = [managedAps objectForKey:@"notificationId"];
447
    
Lidan Hifi's avatar
Lidan Hifi committed
448
    if ([action isEqualToString: RNNotificationCreateAction]
Lidan Hifi's avatar
Lidan Hifi committed
449 450
        && notificationId
        && alert) {
451
        
Lidan Hifi's avatar
Lidan Hifi committed
452
        // trigger new client push notification
453
        UILocalNotification* note = [UILocalNotification new];
Lidan Hifi's avatar
Lidan Hifi committed
454 455
        note.alertTitle = [alert objectForKey:@"title"];
        note.alertBody = [alert objectForKey:@"body"];
456
        note.userInfo = notification;
457
        note.soundName = [managedAps objectForKey:@"sound"];
458
        note.category = [managedAps objectForKey:@"category"];
459
        
Lidan Hifi's avatar
Lidan Hifi committed
460
        [[UIApplication sharedApplication] presentLocalNotificationNow:note];
461
        
Lidan Hifi's avatar
Lidan Hifi committed
462 463 464 465 466
        // Serialize it and store so we can delete it later
        NSData* data = [NSKeyedArchiver archivedDataWithRootObject:note];
        NSString* notificationKey = [self buildNotificationKeyfromNotification:notificationId];
        [[NSUserDefaults standardUserDefaults] setObject:data forKey:notificationKey];
        [[NSUserDefaults standardUserDefaults] synchronize];
467
        
Lidan Hifi's avatar
Lidan Hifi committed
468 469 470 471
        NSLog(@"Local notification was triggered: %@", notificationKey);
    }
}

472
-(void)clearNotificationFromNotificationsCenter:(NSString *)notificationId
Lidan Hifi's avatar
Lidan Hifi committed
473 474 475 476 477
{
    NSString* notificationKey = [self buildNotificationKeyfromNotification:notificationId];
    NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:notificationKey];
    if (data) {
        UILocalNotification* notification = [NSKeyedUnarchiver unarchiveObjectWithData: data];
478
        
Lidan Hifi's avatar
Lidan Hifi committed
479 480 481
        // delete the notification
        [[UIApplication sharedApplication] cancelLocalNotification:notification];
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:notificationKey];
482
        
483
        NSLog(@"Local notification removed: %@", notificationKey);
484
        
Lidan Hifi's avatar
Lidan Hifi committed
485 486 487 488
        return;
    }
}

489
-(NSString *)buildNotificationKeyfromNotification:(NSString *)notificationId
Lidan Hifi's avatar
Lidan Hifi committed
490 491 492 493
{
    return [NSString stringWithFormat:@"%@.%@", [[NSBundle mainBundle] bundleIdentifier], notificationId];
}

494 495 496 497 498 499 500 501
+ (NSString *)deviceTokenToString:(NSData *)deviceToken
{
    NSMutableString *result = [NSMutableString string];
    NSUInteger deviceTokenLength = deviceToken.length;
    const unsigned char *bytes = deviceToken.bytes;
    for (NSUInteger i = 0; i < deviceTokenLength; i++) {
        [result appendFormat:@"%02x", bytes[i]];
    }
502
    
503 504 505
    return [result copy];
}

Lidan Hifi's avatar
Lidan Hifi committed
506 507 508
/*
 * React Native exported methods
 */
509 510 511
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
    NSDictionary * notification = nil;
Yedidya Kennard's avatar
Yedidya Kennard committed
512
    notification = [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification ?
513 514
    [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification :
    [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification;
515
    [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification = nil;
Yedidya Kennard's avatar
Yedidya Kennard committed
516
    [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification = nil;
517 518 519
    resolve(notification);
}

520
RCT_EXPORT_METHOD(completionHandler:(NSString *)completionKey)
521
{
522
    [[RNNotificationsBridgeQueue sharedInstance] completeAction:completionKey];
523 524
}

525 526
RCT_EXPORT_METHOD(registerPushKit)
{
527 528 529 530 531 532 533 534
    dispatch_async(dispatch_get_main_queue(), ^{
        // Create a push registry object
        PKPushRegistry* pushKitRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
        
        // Set the registry delegate to app delegate
        pushKitRegistry.delegate = [[UIApplication sharedApplication] delegate];
        pushKitRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
    });
535 536
}

537

538

539

540 541 542 543 544 545
RCT_EXPORT_METHOD(backgroundTimeRemaining:(RCTResponseSenderBlock)callback)
{
    NSTimeInterval remainingTime = [UIApplication sharedApplication].backgroundTimeRemaining;
    callback(@[ [NSNumber numberWithDouble:remainingTime] ]);
}

546 547
RCT_EXPORT_METHOD(consumeBackgroundQueue)
{
548 549
    // Mark JS Thread as ready
    [RNNotificationsBridgeQueue sharedInstance].jsIsReady = YES;
550
    
551
    // Push actions to JS
552
    [[RNNotificationsBridgeQueue sharedInstance] consumeActionsQueue:^(NSDictionary* action) {
553
        [self checkAndSendEvent:RNNotificationActionReceived body:action];
554
    }];
555
    
556
    // Push background notifications to JS
557
    [[RNNotificationsBridgeQueue sharedInstance] consumeNotificationsQueue:^(NSDictionary* notification) {
558
        [self didReceiveNotificationOnBackgroundState:notification];
559
    }];
560
    
561 562 563
    // Push opened local notifications
    NSDictionary* openedLocalNotification = [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification;
    if (openedLocalNotification) {
564
        [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification = nil;
565
        [self checkAndSendEvent:RNNotificationOpened body:openedLocalNotification];
566
    }
567
    
568 569 570
    // Push opened remote notifications
    NSDictionary* openedRemoteNotification = [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification;
    if (openedRemoteNotification) {
571
        [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification = nil;
572
        [self checkAndSendEvent:RNNotificationOpened body:openedRemoteNotification];
573 574 575
    }
}

576 577 578 579 580 581

RCT_EXPORT_METHOD(cancelAllLocalNotifications)
{
    [RCTSharedApplication() cancelAllLocalNotifications];
}

582 583
RCT_EXPORT_METHOD(isRegisteredForRemoteNotifications:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
584 585 586 587 588 589 590 591
    BOOL ans;
    
    if (TARGET_IPHONE_SIMULATOR) {
        ans = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != 0;
    }
    else {
        ans = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
    }
592 593 594
    resolve(@(ans));
}

Ryan Eberhardt's avatar
Ryan Eberhardt committed
595 596 597 598 599 600 601 602 603 604
RCT_EXPORT_METHOD(checkPermissions:(RCTPromiseResolveBlock) resolve
                  reject:(RCTPromiseRejectBlock) reject) {
    UIUserNotificationSettings *currentSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
    resolve(@{
              @"badge": @((currentSettings.types & UIUserNotificationTypeBadge) > 0),
              @"sound": @((currentSettings.types & UIUserNotificationTypeSound) > 0),
              @"alert": @((currentSettings.types & UIUserNotificationTypeAlert) > 0),
              });
}

605 606 607 608
#if !TARGET_OS_TV

RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
609 610 611 612
    if ([UNUserNotificationCenter class]) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center removeAllDeliveredNotifications];
    }
613 614 615 616
}

RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers)
{
617 618 619 620
    if ([UNUserNotificationCenter class]) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center removeDeliveredNotificationsWithIdentifiers:identifiers];
    }
621 622 623 624
}

RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
625 626 627 628 629 630 631 632 633 634 635
    if ([UNUserNotificationCenter class]) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
            NSMutableArray<NSDictionary *> *formattedNotifications = [NSMutableArray new];
            
            for (UNNotification *notification in notifications) {
                [formattedNotifications addObject:RCTFormatUNNotification(notification)];
            }
            callback(@[formattedNotifications]);
        }];
    }
636 637 638 639
}

#endif !TARGET_OS_TV

Lidan Hifi's avatar
Lidan Hifi committed
640
@end