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

#import <UIKit/UIKit.h>
3
#import <PushKit/PushKit.h>
Gustavo Perdomo's avatar
Gustavo Perdomo committed
4
#if __has_include(<React/RCTBridge.h>)
5 6 7 8 9
  #import <React/RCTBridge.h>
  #import <React/RCTEventDispatcher.h>
  #import "RNNotifications.h"
  #import <React/RCTConvert.h>
  #import <React/RCTUtils.h>
Gustavo Perdomo's avatar
Gustavo Perdomo committed
10 11 12 13 14 15 16
#else
  #import "RCTBridge.h"
  #import "RCTEventDispatcher.h"
  #import "RNNotifications.h"
  #import "RCTConvert.h"
  #import "RCTUtils.h"
#endif
17
#import "RNNotificationsBridgeQueue.h"
18
#import <UserNotifications/UserNotifications.h>
Lidan Hifi's avatar
Lidan Hifi committed
19

20 21
NSString* const RNNotificationCreateAction = @"CREATE";
NSString* const RNNotificationClearAction = @"CLEAR";
Lidan Hifi's avatar
Lidan Hifi committed
22

23
NSString* const RNNotificationsRegistered = @"RNNotificationsRegistered";
24
NSString* const RNNotificationsRegistrationFailed = @"RNNotificationsRegistrationFailed";
25
NSString* const RNPushKitRegistered = @"RNPushKitRegistered";
26 27 28 29
NSString* const RNNotificationReceivedForeground = @"RNNotificationReceivedForeground";
NSString* const RNNotificationReceivedBackground = @"RNNotificationReceivedBackground";
NSString* const RNNotificationOpened = @"RNNotificationOpened";
NSString* const RNNotificationActionTriggered = @"RNNotificationActionTriggered";
Lidan Hifi's avatar
Lidan Hifi committed
30

31
/*
32
 * Converters for Interactive Notifications
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
 */
@implementation RCTConvert (UIUserNotificationActivationMode)
RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
                                                        @"foreground": @(UIUserNotificationActivationModeForeground),
                                                        @"background": @(UIUserNotificationActivationModeBackground)
                                                        }), UIUserNotificationActivationModeForeground, integerValue)
@end

@implementation RCTConvert (UIUserNotificationActionContext)
RCT_ENUM_CONVERTER(UIUserNotificationActionContext, (@{
                                                       @"default": @(UIUserNotificationActionContextDefault),
                                                       @"minimal": @(UIUserNotificationActionContextMinimal)
                                                       }), UIUserNotificationActionContextDefault, integerValue)
@end

@implementation RCTConvert (UIUserNotificationActionBehavior)
/* iOS 9 only */
RCT_ENUM_CONVERTER(UIUserNotificationActionBehavior, (@{
                                                        @"default": @(UIUserNotificationActionBehaviorDefault),
                                                        @"textInput": @(UIUserNotificationActionBehaviorTextInput)
                                                        }), UIUserNotificationActionBehaviorDefault, integerValue)
@end

56 57 58 59
@implementation RCTConvert (UIMutableUserNotificationAction)
+ (UIMutableUserNotificationAction *)UIMutableUserNotificationAction:(id)json
{
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
Lidan Hifi's avatar
Lidan Hifi committed
60

61
    UIMutableUserNotificationAction* action =[UIMutableUserNotificationAction new];
62 63 64 65 66 67
    action.activationMode = [RCTConvert UIUserNotificationActivationMode:details[@"activationMode"]];
    action.behavior = [RCTConvert UIUserNotificationActionBehavior:details[@"behavior"]];
    action.authenticationRequired = [RCTConvert BOOL:details[@"authenticationRequired"]];
    action.destructive = [RCTConvert BOOL:details[@"destructive"]];
    action.title = [RCTConvert NSString:details[@"title"]];
    action.identifier = [RCTConvert NSString:details[@"identifier"]];
Lidan Hifi's avatar
Lidan Hifi committed
68

69 70 71
    return action;
}
@end
72

73 74
@implementation RCTConvert (UIMutableUserNotificationCategory)
+ (UIMutableUserNotificationCategory *)UIMutableUserNotificationCategory:(id)json
75
{
76 77
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];

78
    UIMutableUserNotificationCategory* category = [UIMutableUserNotificationCategory new];
79 80 81
    category.identifier = details[@"identifier"];

    // category actions
82
    NSMutableArray* actions = [NSMutableArray new];
83 84
    for (NSDictionary* actionJson in [RCTConvert NSArray:details[@"actions"]]) {
        [actions addObject:[RCTConvert UIMutableUserNotificationAction:actionJson]];
85
    }
86 87 88 89

    [category setActions:actions forContext:[RCTConvert UIUserNotificationActionContext:details[@"context"]]];

    return category;
90
}
91 92
@end

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
@implementation RCTConvert (UILocalNotification)
+ (UILocalNotification *)UILocalNotification:(id)json
{
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];

    UILocalNotification* notification = [UILocalNotification new];
    notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]];
    notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
    notification.alertTitle = [RCTConvert NSString:details[@"alertTitle"]];
    notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
    notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
    notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]] ?: @{};
    notification.category = [RCTConvert NSString:details[@"category"]];

    return notification;
}
@end

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
static NSDictionary *RCTFormatUNNotification(UNNotification *notification)
{
  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;
}

134 135 136 137 138
@implementation RNNotifications

RCT_EXPORT_MODULE()

@synthesize bridge = _bridge;
Lidan Hifi's avatar
Lidan Hifi committed
139 140 141 142 143 144 145 146 147

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)setBridge:(RCTBridge *)bridge
{
    _bridge = bridge;
Lidan Hifi's avatar
Lidan Hifi committed
148

149 150 151 152 153
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationsRegistered:)
                                                 name:RNNotificationsRegistered
                                               object:nil];

154 155 156 157 158
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationsRegistrationFailed:)
                                                 name:RNNotificationsRegistrationFailed
                                               object:nil];

159 160 161 162 163
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handlePushKitRegistered:)
                                                 name:RNPushKitRegistered
                                               object:nil];

Lidan Hifi's avatar
Lidan Hifi committed
164 165
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationReceivedForeground:)
Lidan Hifi's avatar
Lidan Hifi committed
166
                                                 name:RNNotificationReceivedForeground
Lidan Hifi's avatar
Lidan Hifi committed
167
                                               object:nil];
Lidan Hifi's avatar
Lidan Hifi committed
168

Lidan Hifi's avatar
Lidan Hifi committed
169 170
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationReceivedBackground:)
Lidan Hifi's avatar
Lidan Hifi committed
171
                                                 name:RNNotificationReceivedBackground
Lidan Hifi's avatar
Lidan Hifi committed
172
                                               object:nil];
Lidan Hifi's avatar
Lidan Hifi committed
173

Lidan Hifi's avatar
Lidan Hifi committed
174 175
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationOpened:)
Lidan Hifi's avatar
Lidan Hifi committed
176
                                                 name:RNNotificationOpened
Lidan Hifi's avatar
Lidan Hifi committed
177
                                               object:nil];
178 179 180 181 182

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotificationActionTriggered:)
                                                 name:RNNotificationActionTriggered
                                               object:nil];
183 184 185

    [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification = [_bridge.launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification = [_bridge.launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
Lidan Hifi's avatar
Lidan Hifi committed
186 187 188
}

/*
189
 * Public Methods
Lidan Hifi's avatar
Lidan Hifi committed
190
 */
191 192 193 194 195 196 197 198 199 200 201 202 203 204
+ (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
}

+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationsRegistered
                                                        object:self
                                                      userInfo:@{@"deviceToken": [self deviceTokenToString:deviceToken]}];
}

205 206 207 208 209 210
+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationsRegistrationFailed
                                                        object:self
                                                      userInfo:@{@"code": [NSNumber numberWithInteger:error.code], @"domain": error.domain, @"localizedDescription": error.localizedDescription}];
}

Lidan Hifi's avatar
Lidan Hifi committed
211 212 213
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification
{
    UIApplicationState state = [UIApplication sharedApplication].applicationState;
Lidan Hifi's avatar
Lidan Hifi committed
214

215 216 217 218 219 220 221 222 223 224 225 226 227
    if ([RNNotificationsBridgeQueue sharedInstance].jsIsReady == YES) {
        // JS thread is ready, push the notification to the bridge

        if (state == UIApplicationStateActive) {
            // Notification received foreground
            [self didReceiveNotificationOnForegroundState:notification];
        } else if (state == UIApplicationStateInactive) {
            // Notification opened
            [self didNotificationOpen:notification];
        } else {
            // Notification received background
            [self didReceiveNotificationOnBackgroundState:notification];
        }
Lidan Hifi's avatar
Lidan Hifi committed
228
    } else {
229 230
        // JS thread is not ready - store it in the native notifications queue
        [[RNNotificationsBridgeQueue sharedInstance] postNotification:notification];
Lidan Hifi's avatar
Lidan Hifi committed
231 232 233 234 235 236
    }
}

+ (void)didReceiveLocalNotification:(UILocalNotification *)notification
{
    UIApplicationState state = [UIApplication sharedApplication].applicationState;
Lidan Hifi's avatar
Lidan Hifi committed
237

238 239 240 241
    NSMutableDictionary* newUserInfo = notification.userInfo.mutableCopy;
    [newUserInfo removeObjectForKey:@"__id"];
    notification.userInfo = newUserInfo;

242 243 244
    if (state == UIApplicationStateActive) {
        [self didReceiveNotificationOnForegroundState:notification.userInfo];
    } else if (state == UIApplicationStateInactive) {
Lidan Hifi's avatar
Lidan Hifi committed
245 246 247 248 249 250 251 252
        NSString* notificationId = [notification.userInfo objectForKey:@"notificationId"];
        if (notificationId) {
            [self clearNotificationFromNotificationsCenter:notificationId];
        }
        [self didNotificationOpen:notification.userInfo];
    }
}

253
+ (void)handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler
254
{
255
    [self emitNotificationActionForIdentifier:identifier responseInfo:responseInfo userInfo:notification.userInfo completionHandler:completionHandler];
256 257
}

258
+ (void)handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler
259
{
260
    [self emitNotificationActionForIdentifier:identifier responseInfo:responseInfo userInfo:userInfo completionHandler:completionHandler];
261 262
}

Lidan Hifi's avatar
Lidan Hifi committed
263 264 265 266 267
/*
 * Notification handlers
 */
+ (void)didReceiveNotificationOnForegroundState:(NSDictionary *)notification
{
Lidan Hifi's avatar
Lidan Hifi committed
268
    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationReceivedForeground
Lidan Hifi's avatar
Lidan Hifi committed
269 270 271 272 273 274
                                                        object:self
                                                      userInfo:notification];
}

+ (void)didReceiveNotificationOnBackgroundState:(NSDictionary *)notification
{
275 276 277 278
    NSDictionary* managedAps  = [notification objectForKey:@"managedAps"];
    NSDictionary* alert = [managedAps objectForKey:@"alert"];
    NSString* action = [managedAps objectForKey:@"action"];
    NSString* notificationId = [managedAps objectForKey:@"notificationId"];
Lidan Hifi's avatar
Lidan Hifi committed
279 280 281

    if (action) {
        // create or delete notification
Lidan Hifi's avatar
Lidan Hifi committed
282
        if ([action isEqualToString: RNNotificationCreateAction]
Lidan Hifi's avatar
Lidan Hifi committed
283 284 285
            && notificationId
            && alert) {
            [self dispatchLocalNotificationFromNotification:notification];
Lidan Hifi's avatar
Lidan Hifi committed
286 287

        } else if ([action isEqualToString: RNNotificationClearAction] && notificationId) {
Lidan Hifi's avatar
Lidan Hifi committed
288 289 290
            [self clearNotificationFromNotificationsCenter:notificationId];
        }
    }
Lidan Hifi's avatar
Lidan Hifi committed
291

292 293 294
    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationReceivedBackground
                                                        object:self
                                                      userInfo:notification];
Lidan Hifi's avatar
Lidan Hifi committed
295 296 297 298
}

+ (void)didNotificationOpen:(NSDictionary *)notification
{
Lidan Hifi's avatar
Lidan Hifi committed
299
    [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationOpened
Lidan Hifi's avatar
Lidan Hifi committed
300 301 302 303 304 305 306 307 308
                                                        object:self
                                                      userInfo:notification];
}

/*
 * Helper methods
 */
+ (void)dispatchLocalNotificationFromNotification:(NSDictionary *)notification
{
309 310 311 312
    NSDictionary* managedAps  = [notification objectForKey:@"managedAps"];
    NSDictionary* alert = [managedAps objectForKey:@"alert"];
    NSString* action = [managedAps objectForKey:@"action"];
    NSString* notificationId = [managedAps objectForKey:@"notificationId"];
Lidan Hifi's avatar
Lidan Hifi committed
313 314

    if ([action isEqualToString: RNNotificationCreateAction]
Lidan Hifi's avatar
Lidan Hifi committed
315 316
        && notificationId
        && alert) {
Lidan Hifi's avatar
Lidan Hifi committed
317

Lidan Hifi's avatar
Lidan Hifi committed
318
        // trigger new client push notification
319
        UILocalNotification* note = [UILocalNotification new];
Lidan Hifi's avatar
Lidan Hifi committed
320 321
        note.alertTitle = [alert objectForKey:@"title"];
        note.alertBody = [alert objectForKey:@"body"];
322
        note.userInfo = notification;
323
        note.soundName = [managedAps objectForKey:@"sound"];
324
        note.category = [managedAps objectForKey:@"category"];
Lidan Hifi's avatar
Lidan Hifi committed
325

Lidan Hifi's avatar
Lidan Hifi committed
326
        [[UIApplication sharedApplication] presentLocalNotificationNow:note];
Lidan Hifi's avatar
Lidan Hifi committed
327

Lidan Hifi's avatar
Lidan Hifi committed
328 329 330 331 332
        // 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];
Lidan Hifi's avatar
Lidan Hifi committed
333

Lidan Hifi's avatar
Lidan Hifi committed
334 335 336 337 338 339 340 341 342 343
        NSLog(@"Local notification was triggered: %@", notificationKey);
    }
}

+ (void)clearNotificationFromNotificationsCenter:(NSString *)notificationId
{
    NSString* notificationKey = [self buildNotificationKeyfromNotification:notificationId];
    NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:notificationKey];
    if (data) {
        UILocalNotification* notification = [NSKeyedUnarchiver unarchiveObjectWithData: data];
Lidan Hifi's avatar
Lidan Hifi committed
344

Lidan Hifi's avatar
Lidan Hifi committed
345 346 347
        // delete the notification
        [[UIApplication sharedApplication] cancelLocalNotification:notification];
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:notificationKey];
Lidan Hifi's avatar
Lidan Hifi committed
348

349 350
        NSLog(@"Local notification removed: %@", notificationKey);

Lidan Hifi's avatar
Lidan Hifi committed
351 352 353 354 355 356 357 358 359
        return;
    }
}

+ (NSString *)buildNotificationKeyfromNotification:(NSString *)notificationId
{
    return [NSString stringWithFormat:@"%@.%@", [[NSBundle mainBundle] bundleIdentifier], notificationId];
}

360 361 362 363 364 365 366 367 368 369 370 371
+ (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]];
    }

    return [result copy];
}

372
+ (void)requestPermissionsWithCategories:(NSMutableSet *)categories
373
{
374 375
    UIUserNotificationType types = (UIUserNotificationType) (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert);
    UIUserNotificationSettings* settings = [UIUserNotificationSettings settingsForTypes:types categories:categories];
376

377
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
378 379
}

380
+ (void)emitNotificationActionForIdentifier:(NSString *)identifier responseInfo:(NSDictionary *)responseInfo userInfo:(NSDictionary *)userInfo  completionHandler:(void (^)())completionHandler
381
{
382 383
    NSString* completionKey = [NSString stringWithFormat:@"%@.%@", identifier, [NSString stringWithFormat:@"%d", (long)[[NSDate date] timeIntervalSince1970]]];
    NSMutableDictionary* info = [[NSMutableDictionary alloc] initWithDictionary:@{ @"identifier": identifier, @"completionKey": completionKey }];
384 385 386 387 388

    // add text
    NSString* text = [responseInfo objectForKey:UIUserNotificationActionResponseTypedTextKey];
    if (text != NULL) {
        info[@"text"] = text;
389 390
    }

391 392
    // add notification custom data
    if (userInfo != NULL) {
393
        info[@"notification"] = userInfo;
394
    }
395

396 397
    // 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];
398

399 400 401 402 403
    if ([RNNotificationsBridgeQueue sharedInstance].jsIsReady == YES) {
        [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationActionTriggered
                                                            object:self
                                                          userInfo:info];
    }
404 405
}

406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
+ (void)registerPushKit
{
    // 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];
}

+ (void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
{
    [[NSNotificationCenter defaultCenter] postNotificationName:RNPushKitRegistered
                                                        object:self
                                                      userInfo:@{@"pushKitToken": [self deviceTokenToString:credentials.token]}];
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
{
    [RNNotifications didReceiveRemoteNotification:payload.dictionaryPayload];
}

428 429 430
/*
 * Javascript events
 */
431 432 433 434 435
- (void)handleNotificationsRegistered:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistered" body:notification.userInfo];
}

436 437 438 439 440
- (void)handleNotificationsRegistrationFailed:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistrationFailed" body:notification.userInfo];
}

441 442 443 444 445
- (void)handlePushKitRegistered:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendDeviceEventWithName:@"pushKitRegistered" body:notification.userInfo];
}

Lidan Hifi's avatar
Lidan Hifi committed
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
- (void)handleNotificationReceivedForeground:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendDeviceEventWithName:@"notificationReceivedForeground" body:notification.userInfo];
}

- (void)handleNotificationReceivedBackground:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendDeviceEventWithName:@"notificationReceivedBackground" body:notification.userInfo];
}

- (void)handleNotificationOpened:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendDeviceEventWithName:@"notificationOpened" body:notification.userInfo];
}

461 462 463 464 465
- (void)handleNotificationActionTriggered:(NSNotification *)notification
{
    [_bridge.eventDispatcher sendAppEventWithName:@"notificationActionReceived" body:notification.userInfo];
}

Lidan Hifi's avatar
Lidan Hifi committed
466 467 468
/*
 * React Native exported methods
 */
469
RCT_EXPORT_METHOD(requestPermissionsWithCategories:(NSArray *)json)
Lidan Hifi's avatar
Lidan Hifi committed
470
{
471 472 473
    NSMutableSet* categories = nil;

    if ([json count] > 0) {
474
        categories = [NSMutableSet new];
475 476 477 478 479 480
        for (NSDictionary* categoryJson in json) {
            [categories addObject:[RCTConvert UIMutableUserNotificationCategory:categoryJson]];
        }
    }

    [RNNotifications requestPermissionsWithCategories:categories];
Lidan Hifi's avatar
Lidan Hifi committed
481 482
}

483 484 485 486 487
RCT_EXPORT_METHOD(log:(NSString *)message)
{
    NSLog(message);
}

488
RCT_EXPORT_METHOD(completionHandler:(NSString *)completionKey)
489
{
490
    [[RNNotificationsBridgeQueue sharedInstance] completeAction:completionKey];
491 492
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
RCT_EXPORT_METHOD(abandonPermissions)
{
    [[UIApplication sharedApplication] unregisterForRemoteNotifications];
}

RCT_EXPORT_METHOD(registerPushKit)
{
    [RNNotifications registerPushKit];
}

RCT_EXPORT_METHOD(backgroundTimeRemaining:(RCTResponseSenderBlock)callback)
{
    NSTimeInterval remainingTime = [UIApplication sharedApplication].backgroundTimeRemaining;
    callback(@[ [NSNumber numberWithDouble:remainingTime] ]);
}

509 510
RCT_EXPORT_METHOD(consumeBackgroundQueue)
{
511 512 513 514
    // Mark JS Thread as ready
    [RNNotificationsBridgeQueue sharedInstance].jsIsReady = YES;

    // Push actions to JS
515 516 517 518 519 520
    [[RNNotificationsBridgeQueue sharedInstance] consumeActionsQueue:^(NSDictionary* action) {
        [[NSNotificationCenter defaultCenter] postNotificationName:RNNotificationActionTriggered
                                                            object:self
                                                          userInfo:action];
    }];

521
    // Push background notifications to JS
522
    [[RNNotificationsBridgeQueue sharedInstance] consumeNotificationsQueue:^(NSDictionary* notification) {
523
        [RNNotifications didReceiveRemoteNotification:notification];
524 525
    }];

526 527 528 529 530 531 532 533 534 535 536
    // Push opened local notifications
    NSDictionary* openedLocalNotification = [RNNotificationsBridgeQueue sharedInstance].openedLocalNotification;
    if (openedLocalNotification) {
        [RNNotifications didNotificationOpen:openedLocalNotification];
    }

    // Push opened remote notifications
    NSDictionary* openedRemoteNotification = [RNNotificationsBridgeQueue sharedInstance].openedRemoteNotification;
    if (openedRemoteNotification) {
        [RNNotifications didNotificationOpen:openedRemoteNotification];
    }
537 538
}

539
RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification withId:(NSString *)notificationId)
540
{
541 542 543 544 545
    UILocalNotification* localNotification = [RCTConvert UILocalNotification:notification];
    NSMutableArray* userInfo = localNotification.userInfo.mutableCopy;
    [userInfo setValue:notificationId forKey:@"__id"];
    localNotification.userInfo = userInfo;

546
    if ([notification objectForKey:@"fireDate"] != nil) {
547
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
548
    } else {
549
        [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
550 551 552
    }
}

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId)
{
    for (UILocalNotification* notification in [UIApplication sharedApplication].scheduledLocalNotifications) {
        NSDictionary* notificationInfo = notification.userInfo;

        if ([[notificationInfo objectForKey:@"__id"] isEqualToString:notificationId]) {
            [[UIApplication sharedApplication] cancelLocalNotification:notification];
        }
    }
}

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

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
#if !TARGET_OS_TV

RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
  if ([UNUserNotificationCenter class]) {
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center removeAllDeliveredNotifications];
  }
}

RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers)
{
  if ([UNUserNotificationCenter class]) {
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center removeDeliveredNotificationsWithIdentifiers:identifiers];
  }
}

RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
  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]);
    }];
  }
}

#endif !TARGET_OS_TV

Lidan Hifi's avatar
Lidan Hifi committed
604
@end