RNFIRMessaging.m 27.9 KB
Newer Older
1
#import "RNFIRMessaging.h"
Libin Lu's avatar
init  
Libin Lu committed
2

Libin Lu's avatar
Libin Lu committed
3 4
#import <React/RCTConvert.h>
#import <React/RCTUtils.h>
Libin Lu's avatar
init  
Libin Lu committed
5

Libin Lu's avatar
Libin Lu committed
6 7
@import UserNotifications;

Libin Lu's avatar
init  
Libin Lu committed
8 9 10 11 12 13 14 15 16 17 18
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
#define UIUserNotificationTypeNone  UIRemoteNotificationTypeNone
#define UIUserNotificationType      UIRemoteNotificationType

#endif

NSString *const FCMNotificationReceived = @"FCMNotificationReceived";
Libin Lu's avatar
Libin Lu committed
19 20
NSString *const FCMTokenRefreshed = @"FCMTokenRefreshed";
NSString *const FCMDirectChannelConnectionChanged = @"FCMDirectChannelConnectionChanged";
Libin Lu's avatar
init  
Libin Lu committed
21

Libin Lu's avatar
Libin Lu committed
22 23
@implementation RCTConvert (NSCalendarUnit)

Libin Lu's avatar
Libin Lu committed
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
RCT_ENUM_CONVERTER(NSCalendarUnit,
                   (@{
                      @"year": @(NSCalendarUnitYear),
                      @"month": @(NSCalendarUnitMonth),
                      @"week": @(NSCalendarUnitWeekOfYear),
                      @"day": @(NSCalendarUnitDay),
                      @"hour": @(NSCalendarUnitHour),
                      @"minute": @(NSCalendarUnitMinute)
                      }),
                   0,
                   integerValue)
@end


@implementation RCTConvert (UNNotificationRequest)

+ (UNNotificationRequest *)UNNotificationRequest:(id)json
Libin Lu's avatar
Libin Lu committed
41
{
Libin Lu's avatar
Libin Lu committed
42 43 44 45 46 47
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
    UNMutableNotificationContent *content = [UNMutableNotificationContent new];
    content.title =[RCTConvert NSString:details[@"title"]];
    content.body =[RCTConvert NSString:details[@"body"]];
    NSString* sound = [RCTConvert NSString:details[@"sound"]];
    if(sound != nil){
48 49 50 51 52
        if ([sound isEqual:@"default"]) {
            content.sound = [UNNotificationSound defaultSound];
        } else {
            content.sound = [UNNotificationSound soundNamed:sound];
        }
Libin Lu's avatar
Libin Lu committed
53
    }
Libin Lu's avatar
Libin Lu committed
54 55 56 57 58 59 60 61
    content.categoryIdentifier = [RCTConvert NSString:details[@"click_action"]];
    content.userInfo = details;
    content.badge = [RCTConvert NSNumber:details[@"badge"]];

    NSDate *fireDate = [RCTConvert NSDate:details[@"fire_date"]];

    if(fireDate == nil){
        return [UNNotificationRequest requestWithIdentifier:[RCTConvert NSString:details[@"id"]] content:content trigger:nil];
Libin Lu's avatar
Libin Lu committed
62
    }
Libin Lu's avatar
Libin Lu committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

    NSCalendarUnit interval = [RCTConvert NSCalendarUnit:details[@"repeat_interval"]];
    NSCalendarUnit unitFlags;
    switch (interval) {
        case NSCalendarUnitMinute: {
            unitFlags = NSCalendarUnitSecond;
            break;
        }
        case NSCalendarUnitHour: {
            unitFlags = NSCalendarUnitMinute | NSCalendarUnitSecond;
            break;
        }
        case NSCalendarUnitDay: {
            unitFlags = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
            break;
        }
        case NSCalendarUnitWeekOfYear: {
            unitFlags = NSCalendarUnitWeekday | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
            break;
        }
        case NSCalendarUnitMonth:{
            unitFlags = NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
85
            break;
Libin Lu's avatar
Libin Lu committed
86 87 88
        }
        case NSCalendarUnitYear:{
            unitFlags = NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
89
            break;
Libin Lu's avatar
Libin Lu committed
90 91 92 93
        }
        default:
            unitFlags = NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
            break;
Libin Lu's avatar
Libin Lu committed
94
    }
Libin Lu's avatar
Libin Lu committed
95 96 97
    NSDateComponents *components = [[NSCalendar currentCalendar] components:unitFlags fromDate:fireDate];
    UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:interval != 0];
    return [UNNotificationRequest requestWithIdentifier:[RCTConvert NSString:details[@"id"]] content:content trigger:trigger];
Libin Lu's avatar
Libin Lu committed
98 99 100 101 102 103 104 105
}

@end

@implementation RCTConvert (UILocalNotification)

+ (UILocalNotification *)UILocalNotification:(id)json
{
Libin Lu's avatar
Libin Lu committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
    UILocalNotification *notification = [UILocalNotification new];
    notification.fireDate = [RCTConvert NSDate:details[@"fire_date"]] ?: [NSDate date];
    if([notification respondsToSelector:@selector(setAlertTitle:)]){
        [notification setAlertTitle:[RCTConvert NSString:details[@"title"]]];
    }
    notification.alertBody = [RCTConvert NSString:details[@"body"]];
    notification.alertAction = [RCTConvert NSString:details[@"alert_action"]];
    notification.soundName = [RCTConvert NSString:details[@"sound"]] ?: UILocalNotificationDefaultSoundName;
    notification.userInfo = details;
    notification.category = [RCTConvert NSString:details[@"click_action"]];
    notification.repeatInterval = [RCTConvert NSCalendarUnit:details[@"repeat_interval"]];
    notification.applicationIconBadgeNumber = [RCTConvert NSInteger:details[@"badge"]];
    return notification;
Libin Lu's avatar
Libin Lu committed
120
}
Libin Lu's avatar
Libin Lu committed
121 122 123 124 125 126 127 128

RCT_ENUM_CONVERTER(UIBackgroundFetchResult, (@{
                                               @"UIBackgroundFetchResultNewData": @(UIBackgroundFetchResultNewData),
                                               @"UIBackgroundFetchResultNoData": @(UIBackgroundFetchResultNoData),
                                               @"UIBackgroundFetchResultFailed": @(UIBackgroundFetchResultFailed),
                                               }), UIBackgroundFetchResultNoData, integerValue)

RCT_ENUM_CONVERTER(UNNotificationPresentationOptions, (@{
Libin Lu's avatar
Libin Lu committed
129 130
                                                         @"UNNotificationPresentationOptionAll": @(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound),
                                                         @"UNNotificationPresentationOptionNone": @(UNNotificationPresentationOptionNone)}), UIBackgroundFetchResultNoData, integerValue)
Libin Lu's avatar
Libin Lu committed
131 132 133

@end

134 135 136 137 138 139 140 141 142
@implementation RCTConvert (UNNotificationAction)

typedef NS_ENUM(NSUInteger, UNNotificationActionType) {
    UNNotificationActionTypeDefault,
    UNNotificationActionTypeTextInput
};

+ (UNNotificationAction *) UNNotificationAction:(id)json {
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
143
    
144 145 146 147 148 149 150 151 152 153 154
    NSString *identifier = [RCTConvert NSString: details[@"id"]];
    NSString *title = [RCTConvert NSString: details[@"title"]];
    UNNotificationActionOptions options = [RCTConvert UNNotificationActionOptions: details[@"options"]];
    UNNotificationActionType type = [RCTConvert UNNotificationActionType:details[@"type"]];

    if (type == UNNotificationActionTypeTextInput) {
        NSString *textInputButtonTitle = [RCTConvert NSString: details[@"textInputButtonTitle"]];
        NSString *textInputPlaceholder = [RCTConvert NSString: details[@"textInputPlaceholder"]];

        return [UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:options textInputButtonTitle:textInputButtonTitle textInputPlaceholder:textInputPlaceholder];
    }
155
    
156 157 158
    return [UNNotificationAction actionWithIdentifier:identifier
                                                title:title
                                              options:options];
159
    
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
}

RCT_ENUM_CONVERTER(UNNotificationActionType, (@{
                                                @"UNNotificationActionTypeDefault": @(UNNotificationActionTypeDefault),
                                                @"UNNotificationActionTypeTextInput": @(UNNotificationActionTypeTextInput),
                                                }), UNNotificationActionTypeDefault, integerValue)


RCT_MULTI_ENUM_CONVERTER(UNNotificationActionOptions, (@{
                                                         @"UNNotificationActionOptionAuthenticationRequired": @(UNNotificationActionOptionAuthenticationRequired),
                                                         @"UNNotificationActionOptionDestructive": @(UNNotificationActionOptionDestructive),
                                                         @"UNNotificationActionOptionForeground": @(UNNotificationActionOptionForeground),
                                                         @"UNNotificationActionOptionNone": @(UNNotificationActionOptionNone),
                                                         }), UNNotificationActionOptionNone, integerValue)


@end

@implementation RCTConvert (UNNotificationCategory)


+ (UNNotificationCategory *) UNNotificationCategory:(id)json {
    NSDictionary<NSString *, id> *details = [self NSDictionary:json];
183
    
184
    NSString *identifier = [RCTConvert NSString: details[@"id"]];
185
    
186 187 188 189 190 191 192 193 194 195
    NSMutableArray *actions = [[NSMutableArray alloc] init];
    for (NSDictionary *actionDict in details[@"actions"]) {
        [actions addObject:[RCTConvert UNNotificationAction:actionDict]];
    }

    NSArray<NSString *> *intentIdentifiers = [RCTConvert NSStringArray:details[@"intentIdentifiers"]];
    NSString *hiddenPreviewsBodyPlaceholder = [RCTConvert NSString:details[@"hiddenPreviewsBodyPlaceholder"]];
    UNNotificationCategoryOptions options = [RCTConvert UNNotificationCategoryOptions: details[@"options"]];

    if (hiddenPreviewsBodyPlaceholder) {
196
#if defined(__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
197
          return [UNNotificationCategory categoryWithIdentifier:identifier actions:actions intentIdentifiers:intentIdentifiers hiddenPreviewsBodyPlaceholder:hiddenPreviewsBodyPlaceholder options:options];
198
#endif
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    }

    return [UNNotificationCategory categoryWithIdentifier:identifier actions:actions intentIdentifiers:intentIdentifiers options:options];
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"

RCT_MULTI_ENUM_CONVERTER(UNNotificationCategoryOptions, (@{
                                                           @"UNNotificationCategoryOptionNone": @(UNNotificationCategoryOptionNone),
                                                           @"UNNotificationCategoryOptionCustomDismissAction": @(UNNotificationCategoryOptionCustomDismissAction),
                                                           @"UNNotificationCategoryOptionAllowInCarPlay": @(UNNotificationCategoryOptionAllowInCarPlay),
                                                           @"UNNotificationCategoryOptionHiddenPreviewsShowTitle": @(UNNotificationCategoryOptionHiddenPreviewsShowTitle),
                                                           @"UNNotificationCategoryOptionHiddenPreviewsShowSubtitle": @(UNNotificationCategoryOptionHiddenPreviewsShowSubtitle),
                                                           }), UNNotificationCategoryOptionNone, integerValue)

#pragma clang diagnostic pop


@end

Libin Lu's avatar
Libin Lu committed
220
@interface RNFIRMessaging ()
Libin Lu's avatar
Libin Lu committed
221
@property (nonatomic, strong) NSMutableDictionary *notificationCallbacks;
Libin Lu's avatar
Libin Lu committed
222
@end
Libin Lu's avatar
init  
Libin Lu committed
223

224
@implementation RNFIRMessaging
Libin Lu's avatar
init  
Libin Lu committed
225

226 227 228
static bool jsHandlerRegistered;
static NSMutableArray* pendingNotifications;

Libin Lu's avatar
Libin Lu committed
229
RCT_EXPORT_MODULE();
Libin Lu's avatar
init  
Libin Lu committed
230

Libin Lu's avatar
Libin Lu committed
231
- (NSArray<NSString *> *)supportedEvents {
Libin Lu's avatar
Libin Lu committed
232
    return @[FCMNotificationReceived, FCMTokenRefreshed, FCMDirectChannelConnectionChanged];
Libin Lu's avatar
Libin Lu committed
233 234
}

235
+ (BOOL)requiresMainQueueSetup {
236
    return YES;
237 238
}

Libin Lu's avatar
Libin Lu committed
239
+ (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull RCTRemoteNotificationCallback)completionHandler {
Libin Lu's avatar
Libin Lu committed
240 241 242
    NSMutableDictionary* data = [[NSMutableDictionary alloc] initWithDictionary: userInfo];
    [data setValue:@"remote_notification" forKey:@"_notificationType"];
    [data setValue:@(RCTSharedApplication().applicationState == UIApplicationStateInactive) forKey:@"opened_from_tray"];
243
    [self sendNotificationEventWhenAvailable:@{@"data": data, @"completionHandler": completionHandler}];
Libin Lu's avatar
Libin Lu committed
244 245 246
}

+ (void)didReceiveLocalNotification:(UILocalNotification *)notification {
Libin Lu's avatar
Libin Lu committed
247 248
    NSMutableDictionary* data = [[NSMutableDictionary alloc] initWithDictionary: notification.userInfo];
    [data setValue:@"local_notification" forKey:@"_notificationType"];
249
    [data setValue:@(RCTSharedApplication().applicationState == UIApplicationStateInactive) forKey:@"opened_from_tray"];
250
    [self sendNotificationEventWhenAvailable:@{@"data": data}];
Libin Lu's avatar
Libin Lu committed
251 252
}

Libin Lu's avatar
Libin Lu committed
253
+ (void)didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(nonnull RCTNotificationResponseCallback)completionHandler
Libin Lu's avatar
Libin Lu committed
254
{
Libin Lu's avatar
Libin Lu committed
255 256 257 258 259 260
    NSMutableDictionary* data = [[NSMutableDictionary alloc] initWithDictionary: response.notification.request.content.userInfo];
    [data setValue:@"notification_response" forKey:@"_notificationType"];
    [data setValue:@YES forKey:@"opened_from_tray"];
    if (response.actionIdentifier) {
        [data setValue:response.actionIdentifier forKey:@"_actionIdentifier"];
    }
261 262 263 264

    if ([response isKindOfClass:UNTextInputNotificationResponse.class]) {
        [data setValue:[(UNTextInputNotificationResponse *)response userText] forKey:@"_userText"];
    }
265
    
266
    NSDictionary *userInfo = @{@"data": data, @"completionHandler": completionHandler};
267 268
    [self sendNotificationEventWhenAvailable:userInfo];
  
Libin Lu's avatar
Libin Lu committed
269 270
}

Libin Lu's avatar
Libin Lu committed
271
+ (void)willPresentNotification:(UNNotification *)notification withCompletionHandler:(nonnull RCTWillPresentNotificationCallback)completionHandler
Libin Lu's avatar
Libin Lu committed
272
{
Libin Lu's avatar
Libin Lu committed
273 274
    NSMutableDictionary* data = [[NSMutableDictionary alloc] initWithDictionary: notification.request.content.userInfo];
    [data setValue:@"will_present_notification" forKey:@"_notificationType"];
275 276 277 278 279 280 281 282 283 284 285 286 287 288
    [self sendNotificationEventWhenAvailable:@{@"data": data, @"completionHandler": completionHandler}];
}

+ (void)sendNotificationEventWhenAvailable:(NSDictionary*)data
{
  if(!jsHandlerRegistered){
    // JS hasn't registered callback yet. hold on that
    if(!pendingNotifications){
      pendingNotifications = [NSMutableArray array];
    }
    [pendingNotifications addObject:data];
  } else {
    [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:data];
  }
Libin Lu's avatar
Libin Lu committed
289 290
}

Libin Lu's avatar
init  
Libin Lu committed
291 292
- (void)dealloc
{
Libin Lu's avatar
Libin Lu committed
293
    [[NSNotificationCenter defaultCenter] removeObserver:self];
Libin Lu's avatar
init  
Libin Lu committed
294 295
}

Libin Lu's avatar
Libin Lu committed
296
- (instancetype)init {
Libin Lu's avatar
Libin Lu committed
297
    self = [super init];
298
  
Libin Lu's avatar
Libin Lu committed
299
    [[NSNotificationCenter defaultCenter] addObserver:self
300 301 302
                                           selector:@selector(handleNotificationReceived:)
                                               name:FCMNotificationReceived
                                             object:nil];
Libin Lu's avatar
Libin Lu committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(sendDataMessageFailure:)
     name:FIRMessagingSendErrorNotification object:nil];

    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(sendDataMessageSuccess:)
     name:FIRMessagingSendSuccessNotification object:nil];

    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(connectionStateChanged:)
     name:FIRMessagingConnectionStateChangedNotification object:nil];

    // For iOS 10 data message (sent via FCM)
    dispatch_async(dispatch_get_main_queue(), ^{
        [[FIRMessaging messaging] setDelegate:self];
    });
320
  
Libin Lu's avatar
Libin Lu committed
321
    return self;
Libin Lu's avatar
init  
Libin Lu committed
322 323
}

324
-(void) addListener:(NSString *)eventName {
325
  [super addListener:eventName];
326

327 328 329 330 331 332 333 334 335 336 337 338 339
  if([eventName isEqualToString:FCMNotificationReceived]) {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      jsHandlerRegistered = true;
      
      for (NSDictionary* data in pendingNotifications) {
        [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:data];
      }
      
      [pendingNotifications removeAllObjects];
      
    });
  }
340 341
}

Libin Lu's avatar
Libin Lu committed
342
RCT_EXPORT_METHOD(enableDirectChannel)
Libin Lu's avatar
init  
Libin Lu committed
343
{
Libin Lu's avatar
Libin Lu committed
344
    [[FIRMessaging messaging] setShouldEstablishDirectChannel:@YES];
Libin Lu's avatar
init  
Libin Lu committed
345 346
}

Libin Lu's avatar
Libin Lu committed
347
RCT_EXPORT_METHOD(isDirectChannelEstablished:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
init  
Libin Lu committed
348
{
Libin Lu's avatar
Libin Lu committed
349
    resolve([[FIRMessaging messaging] isDirectChannelEstablished] ? @YES: @NO);
Libin Lu's avatar
init  
Libin Lu committed
350 351
}

Libin Lu's avatar
Libin Lu committed
352
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
Libin Lu committed
353
{
354 355
  NSDictionary* initialNotif;
  NSDictionary *localUserInfo = [[self.bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey] userInfo] mutableCopy];
356
  
357 358 359 360 361 362 363 364 365 366
  NSDictionary *remoteUserInfo = [self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] mutableCopy];
  if(localUserInfo){
    initialNotif = localUserInfo;
  } else if (remoteUserInfo) {
    initialNotif = remoteUserInfo;
  }
  if (initialNotif) {
    [initialNotif setValue:@YES forKey:@"opened_from_tray"];
    resolve(initialNotif);
  } else {
367 368
    
    resolve([self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityTypeKey] copy]);
369
  }
Libin Lu's avatar
Libin Lu committed
370 371
}

372 373


Libin Lu's avatar
Libin Lu committed
374
RCT_EXPORT_METHOD(getAPNSToken:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
init  
Libin Lu committed
375
{
376 377 378 379 380 381 382
    NSData * deviceToken = [FIRMessaging messaging].APNSToken;
    const char *data = [deviceToken bytes];
    NSMutableString *token = [NSMutableString string];
    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
        [token appendFormat:@"%02.2hhX", data[i]];
    }
    resolve([token copy]);
Libin Lu's avatar
init  
Libin Lu committed
383 384
}

Libin Lu's avatar
Libin Lu committed
385
RCT_EXPORT_METHOD(getFCMToken:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
init  
Libin Lu committed
386
{
Libin Lu's avatar
Libin Lu committed
387
    resolve([FIRMessaging messaging].FCMToken);
Libin Lu's avatar
Libin Lu committed
388 389
}

390 391
RCT_EXPORT_METHOD(deleteInstanceId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
392 393 394 395 396 397 398 399
  [[FIRInstanceID instanceID]deleteIDWithHandler:^(NSError * _Nullable error) {
    
    if (error != nil) {
      reject([NSString stringWithFormat:@"%ld",error.code],error.localizedDescription,nil);
    } else {
      resolve(nil);
    }
  }];
400 401
}

Libin Lu's avatar
Libin Lu committed
402
- (void)messaging:(nonnull FIRMessaging *)messaging didRefreshRegistrationToken:(nonnull NSString *)fcmToken {
Libin Lu's avatar
Libin Lu committed
403
    [self sendEventWithName:FCMTokenRefreshed body:fcmToken];
Libin Lu's avatar
init  
Libin Lu committed
404 405
}

Libin Lu's avatar
Libin Lu committed
406
RCT_EXPORT_METHOD(requestPermissions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
init  
Libin Lu committed
407
{
Libin Lu's avatar
Libin Lu committed
408
    if (RCTRunningInAppExtension()) {
Libin Lu's avatar
Libin Lu committed
409
        resolve(nil);
Libin Lu's avatar
Libin Lu committed
410
        return;
Libin Lu's avatar
Libin Lu committed
411
    }
Libin Lu's avatar
Libin Lu committed
412 413 414 415 416 417 418 419 420 421
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
        UIUserNotificationType allNotificationTypes =
        (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
        UIApplication *app = RCTSharedApplication();
        if ([app respondsToSelector:@selector(registerUserNotificationSettings:)]) {
            //iOS 8 or later
            UIUserNotificationSettings *notificationSettings =
            [UIUserNotificationSettings settingsForTypes:(NSUInteger)allNotificationTypes categories:nil];
            [app registerUserNotificationSettings:notificationSettings];
        }
Libin Lu's avatar
Libin Lu committed
422
        resolve(nil);
Libin Lu's avatar
Libin Lu committed
423 424
    } else {
        // iOS 10 or later
Libin Lu's avatar
Libin Lu committed
425
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
Libin Lu's avatar
Libin Lu committed
426 427 428 429 430 431 432 433 434 435
        UNAuthorizationOptions authOptions =
        UNAuthorizationOptionAlert
        | UNAuthorizationOptionSound
        | UNAuthorizationOptionBadge;
        [[UNUserNotificationCenter currentNotificationCenter]
         requestAuthorizationWithOptions:authOptions
         completionHandler:^(BOOL granted, NSError * _Nullable error) {
             if(granted){
                 resolve(nil);
             } else{
436
                 reject(@"notification_error", @"Failed to grant permission", error);
Libin Lu's avatar
Libin Lu committed
437 438 439
             }
         }
         ];
Libin Lu's avatar
Libin Lu committed
440
#endif
Libin Lu's avatar
Libin Lu committed
441 442
    }

443 444 445
    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    });
Libin Lu's avatar
Libin Lu committed
446 447
}

448 449
RCT_EXPORT_METHOD(subscribeToTopic: (NSString*) topic)
{
Libin Lu's avatar
Libin Lu committed
450
    [[FIRMessaging messaging] subscribeToTopic:topic];
451 452 453 454
}

RCT_EXPORT_METHOD(unsubscribeFromTopic: (NSString*) topic)
{
Libin Lu's avatar
Libin Lu committed
455
    [[FIRMessaging messaging] unsubscribeFromTopic:topic];
456 457
}

Libin Lu's avatar
Libin Lu committed
458 459
// Receive data message on iOS 10 devices.
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
Libin Lu's avatar
Libin Lu committed
460
    [self sendEventWithName:FCMNotificationReceived body:[remoteMessage appData]];
Libin Lu's avatar
Libin Lu committed
461 462
}

Libin Lu's avatar
Libin Lu committed
463
RCT_EXPORT_METHOD(presentLocalNotification:(id)data resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
Libin Lu committed
464
{
Libin Lu's avatar
Libin Lu committed
465 466 467 468 469 470 471 472 473 474 475 476
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        UNNotificationRequest* request = [RCTConvert UNNotificationRequest:data];
        [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
            if (!error) {
                resolve(nil);
            }else{
                reject(@"notification_error", @"Failed to present local notificaton", error);
            }
        }];
    }else{
        UILocalNotification* notif = [RCTConvert UILocalNotification:data];
        [RCTSharedApplication() presentLocalNotificationNow:notif];
Libin Lu's avatar
Libin Lu committed
477
        resolve(nil);
Libin Lu's avatar
Libin Lu committed
478
    }
Libin Lu's avatar
Libin Lu committed
479 480
}

Libin Lu's avatar
Libin Lu committed
481
RCT_EXPORT_METHOD(scheduleLocalNotification:(id)data resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
Libin Lu committed
482
{
Libin Lu's avatar
Libin Lu committed
483 484 485 486 487 488 489 490 491 492 493 494
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        UNNotificationRequest* request = [RCTConvert UNNotificationRequest:data];
        [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
            if (!error) {
                resolve(nil);
            }else{
                reject(@"notification_error", @"Failed to present local notificaton", error);
            }
        }];
    }else{
        UILocalNotification* notif = [RCTConvert UILocalNotification:data];
        [RCTSharedApplication() scheduleLocalNotification:notif];
Libin Lu's avatar
Libin Lu committed
495
        resolve(nil);
Libin Lu's avatar
Libin Lu committed
496
    }
Libin Lu's avatar
Libin Lu committed
497 498
}

Libin Lu's avatar
Libin Lu committed
499
RCT_EXPORT_METHOD(removeDeliveredNotification:(NSString*) notificationId)
Libin Lu's avatar
Libin Lu committed
500
{
Libin Lu's avatar
Libin Lu committed
501 502 503
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[notificationId]];
    }
Libin Lu's avatar
Libin Lu committed
504 505 506 507
}

RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
Libin Lu's avatar
Libin Lu committed
508 509 510
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
    } else {
511 512 513
        dispatch_async(dispatch_get_main_queue(), ^{
            [RCTSharedApplication() setApplicationIconBadgeNumber: 0];
        });
Libin Lu's avatar
Libin Lu committed
514
    }
Libin Lu's avatar
Libin Lu committed
515 516
}

Libin Lu's avatar
Libin Lu committed
517 518
RCT_EXPORT_METHOD(cancelAllLocalNotifications)
{
Libin Lu's avatar
Libin Lu committed
519 520 521 522 523
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
    } else {
        [RCTSharedApplication() cancelAllLocalNotifications];
    }
Libin Lu's avatar
Libin Lu committed
524 525 526 527
}

RCT_EXPORT_METHOD(cancelLocalNotification:(NSString*) notificationId)
{
Libin Lu's avatar
Libin Lu committed
528 529 530 531 532 533 534 535 536
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[notificationId]];
    }else {
        for (UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications) {
            NSDictionary<NSString *, id> *notificationInfo = notification.userInfo;
            if([notificationId isEqualToString:[notificationInfo valueForKey:@"id"]]){
                [[UIApplication sharedApplication] cancelLocalNotification:notification];
            }
        }
Libin Lu's avatar
Libin Lu committed
537 538 539
    }
}

Libin Lu's avatar
Libin Lu committed
540
RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
Libin Lu committed
541
{
Libin Lu's avatar
Libin Lu committed
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
    if([UNUserNotificationCenter currentNotificationCenter] != nil){
        [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
            NSMutableArray* list = [[NSMutableArray alloc] init];
            for(UNNotificationRequest * notif in requests){
                UNNotificationContent *content = notif.content;
                [list addObject:content.userInfo];
            }
            resolve(list);
        }];
    }else{
        NSMutableArray* list = [[NSMutableArray alloc] init];
        for(UILocalNotification * notif in [RCTSharedApplication() scheduledLocalNotifications]){
            [list addObject:notif.userInfo];
        }
        resolve(list);
Libin Lu's avatar
Libin Lu committed
557 558 559
    }
}

560 561 562 563 564 565 566 567 568 569 570 571 572 573
RCT_EXPORT_METHOD(setNotificationCategories:(NSArray *)categories)
{
    if([UNUserNotificationCenter currentNotificationCenter] != nil) {
        NSMutableSet *categoriesSet = [[NSMutableSet alloc] init];

        for(NSDictionary *categoryDict in categories) {
            UNNotificationCategory *category = [RCTConvert UNNotificationCategory:categoryDict];
            [categoriesSet addObject:category];
        }

        [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categoriesSet];
    }
}

Libin Lu's avatar
Libin Lu committed
574
RCT_EXPORT_METHOD(setBadgeNumber: (NSInteger) number)
Libin Lu's avatar
Libin Lu committed
575
{
576 577 578
    dispatch_async(dispatch_get_main_queue(), ^{
        [RCTSharedApplication() setApplicationIconBadgeNumber:number];
    });
Libin Lu's avatar
Libin Lu committed
579 580
}

Libin Lu's avatar
Libin Lu committed
581
RCT_EXPORT_METHOD(getBadgeNumber: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
Libin Lu's avatar
Libin Lu committed
582
{
Libin Lu's avatar
Libin Lu committed
583
    resolve(@([RCTSharedApplication() applicationIconBadgeNumber]));
Libin Lu's avatar
Libin Lu committed
584 585
}

586 587
RCT_EXPORT_METHOD(send:(NSString*)senderId withPayload:(NSDictionary *)message)
{
Libin Lu's avatar
Libin Lu committed
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
    NSMutableDictionary * mMessage = [message mutableCopy];
    NSMutableDictionary * upstreamMessage = [[NSMutableDictionary alloc] init];
    for (NSString* key in mMessage) {
        upstreamMessage[key] = [NSString stringWithFormat:@"%@", [mMessage valueForKey:key]];
    }

    NSDictionary *imMessage = [NSDictionary dictionaryWithDictionary:upstreamMessage];

    int64_t ttl = 3600;
    NSString * receiver = [NSString stringWithFormat:@"%@@gcm.googleapis.com", senderId];

    NSUUID *uuid = [NSUUID UUID];
    NSString * messageID = [uuid UUIDString];

    [[FIRMessaging messaging]sendMessage:imMessage to:receiver withMessageID:messageID timeToLive:ttl];
603 604
}

Libin Lu's avatar
Libin Lu committed
605
RCT_EXPORT_METHOD(finishRemoteNotification: (NSString *)completionHandlerId fetchResult:(UIBackgroundFetchResult)result){
Libin Lu's avatar
Libin Lu committed
606 607 608 609 610 611 612
    RCTRemoteNotificationCallback completionHandler = self.notificationCallbacks[completionHandlerId];
    if (!completionHandler) {
        RCTLogError(@"There is no completion handler with completionHandlerId: %@", completionHandlerId);
        return;
    }
    completionHandler(result);
    [self.notificationCallbacks removeObjectForKey:completionHandlerId];
Libin Lu's avatar
Libin Lu committed
613 614 615
}

RCT_EXPORT_METHOD(finishWillPresentNotification: (NSString *)completionHandlerId fetchResult:(UNNotificationPresentationOptions)result){
Libin Lu's avatar
Libin Lu committed
616 617 618 619 620 621 622
    RCTWillPresentNotificationCallback completionHandler = self.notificationCallbacks[completionHandlerId];
    if (!completionHandler) {
        RCTLogError(@"There is no completion handler with completionHandlerId: %@", completionHandlerId);
        return;
    }
    completionHandler(result);
    [self.notificationCallbacks removeObjectForKey:completionHandlerId];
Libin Lu's avatar
Libin Lu committed
623 624 625
}

RCT_EXPORT_METHOD(finishNotificationResponse: (NSString *)completionHandlerId){
Libin Lu's avatar
Libin Lu committed
626 627 628 629 630 631 632
    RCTNotificationResponseCallback completionHandler = self.notificationCallbacks[completionHandlerId];
    if (!completionHandler) {
        RCTLogError(@"There is no completion handler with completionHandlerId: %@", completionHandlerId);
        return;
    }
    completionHandler();
    [self.notificationCallbacks removeObjectForKey:completionHandlerId];
Libin Lu's avatar
Libin Lu committed
633 634
}

Libin Lu's avatar
Libin Lu committed
635
- (void)handleNotificationReceived:(NSNotification *)notification
Libin Lu's avatar
init  
Libin Lu committed
636
{
Libin Lu's avatar
Libin Lu committed
637 638 639 640 641 642 643 644 645 646
    id completionHandler = notification.userInfo[@"completionHandler"];
    NSMutableDictionary* data = notification.userInfo[@"data"];
    if(completionHandler != nil){
        NSString *completionHandlerId = [[NSUUID UUID] UUIDString];
        if (!self.notificationCallbacks) {
            // Lazy initialization
            self.notificationCallbacks = [NSMutableDictionary dictionary];
        }
        self.notificationCallbacks[completionHandlerId] = completionHandler;
        data[@"_completionHandlerId"] = completionHandlerId;
Libin Lu's avatar
Libin Lu committed
647
    }
Libin Lu's avatar
Libin Lu committed
648
    [self sendEventWithName:FCMNotificationReceived body:data];
Libin Lu's avatar
init  
Libin Lu committed
649 650
}

Libin Lu's avatar
Libin Lu committed
651
- (void)sendDataMessageFailure:(NSNotification *)notification
652
{
Libin Lu's avatar
Libin Lu committed
653 654 655
    NSString *messageID = (NSString *)notification.userInfo[@"messageID"];

    NSLog(@"sendDataMessageFailure: %@", messageID);
656 657
}

Libin Lu's avatar
Libin Lu committed
658
- (void)sendDataMessageSuccess:(NSNotification *)notification
659
{
Libin Lu's avatar
Libin Lu committed
660 661 662
    NSString *messageID = (NSString *)notification.userInfo[@"messageID"];

    NSLog(@"sendDataMessageSuccess: %@", messageID);
663 664
}

Libin Lu's avatar
Libin Lu committed
665 666
- (void)connectionStateChanged:(NSNotification *)notification
{
Libin Lu's avatar
Libin Lu committed
667 668
    [self sendEventWithName:FCMDirectChannelConnectionChanged body:[FIRMessaging messaging].isDirectChannelEstablished ? @YES: @NO];
    NSLog(@"connectionStateChanged: %@", [FIRMessaging messaging].isDirectChannelEstablished ? @"connected": @"disconnected");
Libin Lu's avatar
Libin Lu committed
669 670
}

Libin Lu's avatar
init  
Libin Lu committed
671
@end