#import "RNFIRMessaging.h" #import "RCTBridge.h" #import "RCTConvert.h" #import "RCTEventDispatcher.h" #import "RCTUtils.h" @import UserNotifications; #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"; @implementation RCTConvert (NSCalendarUnit) + (NSCalendarUnit *)NSCalendarUnit:(id)json { NSString* key = [self NSString:json]; if([key isEqualToString:@"minute"]){ return NSCalendarUnitMinute; } if([key isEqualToString:@"second"]){ return NSCalendarUnitSecond; } if([key isEqualToString:@"day"]){ return NSCalendarUnitDay; } if([key isEqualToString:@"month"]){ return NSCalendarUnitMonth; } if([key isEqualToString:@"week"]){ return NSCalendarUnitWeekOfYear; } if([key isEqualToString:@"year"]){ return NSCalendarUnitYear; } return 0; } @end @implementation RCTConvert (UILocalNotification) + (UILocalNotification *)UILocalNotification:(id)json { NSDictionary *details = [self NSDictionary:json]; UILocalNotification *notification = [UILocalNotification new]; notification.fireDate = [RCTConvert NSDate:details[@"fire_date"]] ?: [NSDate date]; notification.alertTitle = [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; } @end @implementation RNFIRMessaging RCT_EXPORT_MODULE() @synthesize bridge = _bridge; - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotificationReceived:) name:FCMNotificationReceived object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnectFCM) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectToFCM) name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTokenRefresh) name:kFIRInstanceIDTokenRefreshNotification object:nil]; // For iOS 10 data message (sent via FCM) [[FIRMessaging messaging] setRemoteMessageDelegate:self]; } - (void)connectToFCM { [[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) { if (error != nil) { NSLog(@"Unable to connect to FCM. %@", error); } else { NSLog(@"Connected to FCM."); } }]; } - (void)disconnectFCM { [[FIRMessaging messaging] disconnect]; NSLog(@"Disconnected from FCM"); } RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){ NSDictionary *localUserInfo = _bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; if(localUserInfo){ resolve([localUserInfo copy]); return; } resolve([_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy]); } RCT_EXPORT_METHOD(getFCMToken:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { resolve([[FIRInstanceID instanceID] token]); } RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSMutableArray* list = [[NSMutableArray alloc] init]; for(UILocalNotification * notif in [RCTSharedApplication() scheduledLocalNotifications]){ NSString* interval; switch(notif.repeatInterval){ case NSCalendarUnitMinute: interval = @"minute"; break; case NSCalendarUnitSecond: interval = @"second"; break; case NSCalendarUnitDay: interval = @"day"; break; case NSCalendarUnitMonth: interval = @"month"; break; case NSCalendarUnitWeekOfYear: interval = @"week"; break; case NSCalendarUnitYear: interval = @"year"; break; } NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary]; if (notif.fireDate) { NSDateFormatter *formatter = [NSDateFormatter new]; [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"]; NSString *fireDateString = [formatter stringFromDate:notif.fireDate]; formattedLocalNotification[@"fire_date"] = fireDateString; } formattedLocalNotification[@"alert_action"] = RCTNullIfNil(notif.alertAction); formattedLocalNotification[@"body"] = RCTNullIfNil(notif.alertBody); formattedLocalNotification[@"title"] = RCTNullIfNil(notif.alertTitle); formattedLocalNotification[@"badge"] = @(notif.applicationIconBadgeNumber); formattedLocalNotification[@"click_action"] = RCTNullIfNil(notif.category); formattedLocalNotification[@"sound"] = RCTNullIfNil(notif.soundName); formattedLocalNotification[@"repeat_interval"] = RCTNullIfNil(interval); formattedLocalNotification[@"data"] = RCTNullIfNil(RCTJSONClean(notif.userInfo)); [list addObject:formattedLocalNotification]; } resolve(list); } - (void) onTokenRefresh { [_bridge.eventDispatcher sendDeviceEventWithName:@"FCMTokenRefreshed" body:[[FIRInstanceID instanceID] token]]; } RCT_EXPORT_METHOD(requestPermissions) { if (RCTRunningInAppExtension()) { return; } 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]; } else { //iOS 7 or below [app registerForRemoteNotificationTypes:(NSUInteger)allNotificationTypes]; } } else { // iOS 10 or later #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { } ]; #endif } [[UIApplication sharedApplication] registerForRemoteNotifications]; } #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Receive data message on iOS 10 devices. - (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage { [_bridge.eventDispatcher sendDeviceEventWithName:FCMNotificationReceived body:[remoteMessage appData]]; } #endif RCT_EXPORT_METHOD(subscribeToTopic: (NSString*) topic) { [[FIRMessaging messaging] subscribeToTopic:topic]; } RCT_EXPORT_METHOD(unsubscribeFromTopic: (NSString*) topic) { [[FIRMessaging messaging] unsubscribeFromTopic:topic]; } RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification) { [RCTSharedApplication() presentLocalNotificationNow:notification]; } RCT_EXPORT_METHOD(scheduleLocalNotification:(UILocalNotification *)notification) { [RCTSharedApplication() scheduleLocalNotification:notification]; } RCT_EXPORT_METHOD(cancelAllLocalNotifications) { [RCTSharedApplication() cancelAllLocalNotifications]; } RCT_EXPORT_METHOD(cancelLocalNotification:(NSString*) notificationId) { for (UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications) { NSDictionary *notificationInfo = notification.userInfo; if([notificationId isEqualToString:[notificationInfo valueForKey:@"id"]]){ [[UIApplication sharedApplication] cancelLocalNotification:notification]; } } } RCT_EXPORT_METHOD(setBadgeNumber: (NSInteger*) number) { [RCTSharedApplication() setApplicationIconBadgeNumber:number]; } RCT_EXPORT_METHOD(getBadgeNumber: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { resolve(@([RCTSharedApplication() applicationIconBadgeNumber])); } - (void)handleNotificationReceived:(NSNotification *)notification { if([notification.userInfo valueForKey:@"opened_from_tray"] == nil){ NSMutableDictionary *data = [[NSMutableDictionary alloc]initWithDictionary: notification.userInfo]; [data setValue:@(RCTSharedApplication().applicationState == UIApplicationStateInactive) forKey:@"opened_from_tray"]; [_bridge.eventDispatcher sendDeviceEventWithName:FCMNotificationReceived body:data]; }else{ [_bridge.eventDispatcher sendDeviceEventWithName:FCMNotificationReceived body:notification.userInfo]; } } @end