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
//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
250 251 252 253 254
    if ([response isKindOfClass:[UNTextInputNotificationResponse class]]) {
        NSString* text = ((UNTextInputNotificationResponse*)response).userText;
        if (text != NULL) {
            info[@"text"] = text;
        }
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    }
    
    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;
    }
    
}
275

276 277 278 279 280
- (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
281

282 283 284 285 286
- (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
287

288 289 290 291 292 293 294 295 296 297 298 299
//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];
    }
}
300

301 302 303 304 305 306 307 308 309 310 311 312 313 314
-(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];
    }
}
315

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

321 322 323 324 325
////////////////////////////////////////////////////////////////
#pragma mark ecents emitter side
////////////////////////////////////////////////////////////////

- (NSArray<NSString *> *)supportedEvents
326
{
327 328 329 330 331
    
    return @[ RNNotificationsRegistered,
              RNNotificationsRegistrationFailed,
              RNNotificationReceivedForeground,
              RNNotificationReceivedBackground,
Artal Druk's avatar
Artal Druk committed
332 333 334 335
              RNNotificationOpened,
              RNNotificationActionReceived,
              RNPushKitRegistered,
              RNNotificationActionTriggered];
336
    
337 338
}

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

347 348 349
- (void)stopObserving
{
    _hasListeners = NO;
350 351
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

542

543

544

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

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

581 582 583 584 585 586

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

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

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

610 611 612 613
#if !TARGET_OS_TV

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

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

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

#endif !TARGET_OS_TV

Lidan Hifi's avatar
Lidan Hifi committed
645
@end