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
}

175 176


Lidan Hifi's avatar
Lidan Hifi committed
177 178
- (void)setBridge:(RCTBridge *)bridge
{
179 180 181 182 183 184 185 186
    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
187

188 189 190
////////////////////////////////////////////////////////////////
#pragma mark private functions
////////////////////////////////////////////////////////////////
191

192 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
+ (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);
    });
}
239

240 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
//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;
    }
    
}
271

272 273 274 275 276
- (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
277

278 279 280 281 282
- (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
283

284 285 286 287 288 289 290 291 292 293 294 295
//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];
    }
}
296

297 298 299 300 301 302 303 304 305 306 307 308 309 310
-(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];
    }
}
311

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

317 318 319 320 321
////////////////////////////////////////////////////////////////
#pragma mark ecents emitter side
////////////////////////////////////////////////////////////////

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

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

340 341 342
- (void)stopObserving
{
    _hasListeners = NO;
343 344
}

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

350 351 352 353 354 355 356 357 358 359 360 361 362
////////////////////////////////////////////////////////////////
#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]];
363
        }
Lidan Hifi's avatar
Lidan Hifi committed
364
    }
365
    [RNNotifications requestPermissionsWithCategories:categories];
Lidan Hifi's avatar
Lidan Hifi committed
366 367
}

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

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

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

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

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

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

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

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

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

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

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

492 493 494 495 496 497 498 499
+ (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]];
    }
500
    
501 502 503
    return [result copy];
}

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

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

523 524
RCT_EXPORT_METHOD(registerPushKit)
{
525 526 527 528 529 530 531 532
    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];
    });
533 534
}

535

536

537

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

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

574 575 576 577 578 579

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

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

Ryan Eberhardt's avatar
Ryan Eberhardt committed
593 594 595 596 597 598 599 600 601 602
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),
              });
}

603 604 605 606
#if !TARGET_OS_TV

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

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

RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
623 624 625 626 627 628 629 630 631 632 633
    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]);
        }];
    }
634 635 636 637
}

#endif !TARGET_OS_TV

Lidan Hifi's avatar
Lidan Hifi committed
638
@end