RNNotifications.m 26.2 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
    
    return @[ RNNotificationsRegistered,
              RNNotificationsRegistrationFailed,
              RNNotificationReceivedForeground,
              RNNotificationReceivedBackground,
Artal Druk's avatar
Artal Druk committed
330 331 332 333
              RNNotificationOpened,
              RNNotificationActionReceived,
              RNPushKitRegistered,
              RNNotificationActionTriggered];
334
    
335 336
}

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

345 346 347
- (void)stopObserving
{
    _hasListeners = NO;
348 349
}

350
- (void)startObserving
Lidan Hifi's avatar
Lidan Hifi committed
351
{
352 353
    _hasListeners = YES;
}
Lidan Hifi's avatar
Lidan Hifi committed
354

355 356 357 358 359 360 361 362 363 364 365 366 367
////////////////////////////////////////////////////////////////
#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]];
368
        }
Lidan Hifi's avatar
Lidan Hifi committed
369
    }
370
    [RNNotifications requestPermissionsWithCategories:categories];
Lidan Hifi's avatar
Lidan Hifi committed
371 372
}

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

379 380 381 382 383
RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId)
{
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center removePendingNotificationRequestsWithIdentifiers:@[notificationId]];
}
384

385 386 387
RCT_EXPORT_METHOD(abandonPermissions)
{
    [[UIApplication sharedApplication] unregisterForRemoteNotifications];
Lidan Hifi's avatar
Lidan Hifi committed
388 389
}

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

396
RCT_EXPORT_METHOD(setBadgesCount:(int)count)
397
{
398
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:count];
399 400
}

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

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

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

/*
 * Helper methods
 */
444
-(void)dispatchLocalNotificationFromNotification:(NSDictionary *)notification
Lidan Hifi's avatar
Lidan Hifi committed
445
{
446 447 448 449
    NSDictionary* managedAps  = [notification objectForKey:@"managedAps"];
    NSDictionary* alert = [managedAps objectForKey:@"alert"];
    NSString* action = [managedAps objectForKey:@"action"];
    NSString* notificationId = [managedAps objectForKey:@"notificationId"];
450
    
Lidan Hifi's avatar
Lidan Hifi committed
451
    if ([action isEqualToString: RNNotificationCreateAction]
Lidan Hifi's avatar
Lidan Hifi committed
452 453
        && notificationId
        && alert) {
454
        
Lidan Hifi's avatar
Lidan Hifi committed
455
        // trigger new client push notification
456
        UILocalNotification* note = [UILocalNotification new];
Lidan Hifi's avatar
Lidan Hifi committed
457 458
        note.alertTitle = [alert objectForKey:@"title"];
        note.alertBody = [alert objectForKey:@"body"];
459
        note.userInfo = notification;
460
        note.soundName = [managedAps objectForKey:@"sound"];
461
        note.category = [managedAps objectForKey:@"category"];
462
        
Lidan Hifi's avatar
Lidan Hifi committed
463
        [[UIApplication sharedApplication] presentLocalNotificationNow:note];
464
        
Lidan Hifi's avatar
Lidan Hifi committed
465 466 467 468 469
        // 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];
470
        
Lidan Hifi's avatar
Lidan Hifi committed
471 472 473 474
        NSLog(@"Local notification was triggered: %@", notificationKey);
    }
}

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

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

497 498 499 500 501 502 503 504
+ (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]];
    }
505
    
506 507 508
    return [result copy];
}

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

523
RCT_EXPORT_METHOD(completionHandler:(NSString *)completionKey)
524
{
525
    [[RNNotificationsBridgeQueue sharedInstance] completeAction:completionKey];
526 527
}

528 529
RCT_EXPORT_METHOD(registerPushKit)
{
530 531 532 533 534 535 536 537
    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];
    });
538 539
}

540

541

542

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

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

579 580 581 582 583 584

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

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

Ryan Eberhardt's avatar
Ryan Eberhardt committed
598 599 600 601 602 603 604 605 606 607
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),
              });
}

608 609 610 611
#if !TARGET_OS_TV

RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
612 613 614 615
    if ([UNUserNotificationCenter class]) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center removeAllDeliveredNotifications];
    }
616 617 618 619
}

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

RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
628 629 630 631 632 633 634 635 636 637 638
    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]);
        }];
    }
639 640 641 642
}

#endif !TARGET_OS_TV

Lidan Hifi's avatar
Lidan Hifi committed
643
@end