diff --git a/Examples/simple-fcm-client/app/PushController.js b/Examples/simple-fcm-client/app/PushController.js index e7d52dbf1281d615518b2499ce3263bdd90d1728..bd6011f6983832b05b16a34a1bb4ffddb441b726 100644 --- a/Examples/simple-fcm-client/app/PushController.js +++ b/Examples/simple-fcm-client/app/PushController.js @@ -56,6 +56,16 @@ export default class PushController extends Component { console.log("TOKEN (refreshUnsubscribe)", token); this.props.onChangeToken(token); }); + + // direct channel related methods are ios only + // directly channel is truned off in iOS by default, this method enables it + FCM.enableDirectChannel(); + this.channelConnectionListener = FCM.on(FCMEvent.DirectChannelConnectionChanged, (data) => { + console.log('direct channel connected' + data); + }); + setTimeout(function() { + FCM.isDirectChannelEstablished().then(d => console.log(d)); + }, 1000); } showLocalNotification(notif) { diff --git a/index.d.ts b/index.d.ts index 855de54f0a26603f5f56362f5903862a9231bbe1..1245a4b92bcbaf822eb5680f86502834d6c08ad3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,9 +1,10 @@ declare module "react-native-fcm" { - type FCMEventType = "FCMTokenRefreshed" | "FCMNotificationReceived"; + type FCMEventType = "FCMTokenRefreshed" | "FCMNotificationReceived" | 'FCMDirectChannelConnectionChanged'; export module FCMEvent { const RefreshToken = "FCMTokenRefreshed"; const Notification = "FCMNotificationReceived"; + const DirectChannelConnectionChanged: 'FCMDirectChannelConnectionChanged' } export module RemoteNotificationResult { @@ -79,6 +80,10 @@ declare module "react-native-fcm" { static setBadgeNumber(badge: number): void; static getBadgeNumber(): Promise; static send(id: string, data: any): void; + + static enableDirectChannel(): void + static isDirectChannelEstablished(): Promise + static getAPNSToken(): Promise } export default FCM; diff --git a/index.js b/index.js index 10361c13647019aad95ff8d93b49e59af2bcaa94..c139729cf6f4c4134d2a87ee23619628b2478ca7 100644 --- a/index.js +++ b/index.js @@ -1,106 +1,121 @@ -import {NativeModules, DeviceEventEmitter, Platform} from 'react-native'; +import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; + +const EventEmitter = new NativeEventEmitter(NativeModules.RNFIRMessaging); export const FCMEvent = { RefreshToken: 'FCMTokenRefreshed', - Notification: 'FCMNotificationReceived' -} + Notification: 'FCMNotificationReceived', + DirectChannelConnectionChanged: 'FCMDirectChannelConnectionChanged' +}; export const RemoteNotificationResult = { NewData: 'UIBackgroundFetchResultNewData', NoData: 'UIBackgroundFetchResultNoData', ResultFailed: 'UIBackgroundFetchResultFailed' -} +}; export const WillPresentNotificationResult = { All: 'UNNotificationPresentationOptionAll', None: 'UNNotificationPresentationOptionNone' -} +}; export const NotificationType = { Remote: 'remote_notification', NotificationResponse: 'notification_response', WillPresent: 'will_present_notification', Local: 'local_notification' -} +}; const RNFIRMessaging = NativeModules.RNFIRMessaging; const FCM = {}; FCM.getInitialNotification = () => { - return RNFIRMessaging.getInitialNotification(); -} + return RNFIRMessaging.getInitialNotification(); +}; + +FCM.enableDirectChannel = () => { + if (Platform.OS === 'ios') { + return RNFIRMessaging.enableDirectChannel(); + } +}; + +FCM.isDirectChannelEstablished = () => { + return Platform.OS === 'ios' ? RNFIRMessaging.isDirectChannelEstablished() : Promise.resolve(true); +}; FCM.getFCMToken = () => { - return RNFIRMessaging.getFCMToken(); + return RNFIRMessaging.getFCMToken(); +}; + +FCM.getAPNSToken = () => { + if (Platform.OS === 'ios') { + return RNFIRMessaging.getAPNSToken(); + } }; FCM.requestPermissions = () => { - return RNFIRMessaging.requestPermissions(); + return RNFIRMessaging.requestPermissions(); }; FCM.presentLocalNotification = (details) => { - details.id = details.id || new Date().getTime().toString() - details.local_notification = true; - RNFIRMessaging.presentLocalNotification(details); + details.id = details.id || new Date().getTime().toString(); + details.local_notification = true; + RNFIRMessaging.presentLocalNotification(details); }; FCM.scheduleLocalNotification = function(details) { - if (!details.id) { - throw new Error("id is required for scheduled notification"); - } - if (!details.fire_date) { - throw new Error("fire_date is required for scheduled notification"); - } - details.local_notification = true; - RNFIRMessaging.scheduleLocalNotification(details); + if (!details.id) { + throw new Error('id is required for scheduled notification'); + } + details.local_notification = true; + RNFIRMessaging.scheduleLocalNotification(details); }; FCM.getScheduledLocalNotifications = function() { - return RNFIRMessaging.getScheduledLocalNotifications(); + return RNFIRMessaging.getScheduledLocalNotifications(); }; FCM.cancelLocalNotification = (notificationID) => { - if(!notificationID){ - return; - } - RNFIRMessaging.cancelLocalNotification(notificationID); + if (!notificationID) { + return; + } + RNFIRMessaging.cancelLocalNotification(notificationID); }; FCM.cancelAllLocalNotifications = () => { - RNFIRMessaging.cancelAllLocalNotifications(); + RNFIRMessaging.cancelAllLocalNotifications(); }; FCM.removeDeliveredNotification = (notificationID) => { - if(!notificationID){ - return; - } - RNFIRMessaging.removeDeliveredNotification(notificationID); -} + if (!notificationID) { + return; + } + RNFIRMessaging.removeDeliveredNotification(notificationID); +}; FCM.removeAllDeliveredNotifications = () => { - RNFIRMessaging.removeAllDeliveredNotifications(); -} + RNFIRMessaging.removeAllDeliveredNotifications(); +}; FCM.setBadgeNumber = (number) => { - RNFIRMessaging.setBadgeNumber(number); -} + RNFIRMessaging.setBadgeNumber(number); +}; FCM.getBadgeNumber = () => { - return RNFIRMessaging.getBadgeNumber(); -} - + return RNFIRMessaging.getBadgeNumber(); +}; -function finish(result){ - if(Platform.OS !== 'ios'){ +function finish(result) { + if (Platform.OS !== 'ios') { return; } - if(!this._finishCalled && this._completionHandlerId){ + if (!this._finishCalled && this._completionHandlerId) { this._finishCalled = true; - switch(this._notificationType){ + switch (this._notificationType) { case NotificationType.Remote: result = result || RemoteNotificationResult.NoData; - if(!Object.values(RemoteNotificationResult).includes(result)){ + if (!Object.values(RemoteNotificationResult).includes(result)) { throw new Error(`Invalid RemoteNotificationResult, use import {RemoteNotificationResult} from 'react-native-fcm' to avoid typo`); } RNFIRMessaging.finishRemoteNotification(this._completionHandlerId, result); @@ -110,7 +125,7 @@ function finish(result){ return; case NotificationType.WillPresent: result = result || (this.show_in_foreground ? WillPresentNotificationResult.All : WillPresentNotificationResult.None); - if(!Object.values(WillPresentNotificationResult).includes(result)){ + if (!Object.values(WillPresentNotificationResult).includes(result)) { throw new Error(`Invalid WillPresentNotificationResult, make sure you use import {WillPresentNotificationResult} from 'react-native-fcm' to avoid typo`); } RNFIRMessaging.finishWillPresentNotification(this._completionHandlerId, result); @@ -122,32 +137,37 @@ function finish(result){ } FCM.on = (event, callback) => { - if (!Object.values(FCMEvent).includes(event)) { - throw new Error(`Invalid FCM event subscription, use import {FCMEvent} from 'react-native-fcm' to avoid typo`); - }; - - if(event === FCMEvent.Notification){ - return DeviceEventEmitter.addListener(event, async(data)=>{ - data.finish = finish; + if (!Object.values(FCMEvent).includes(event)) { + throw new Error(`Invalid FCM event subscription, use import {FCMEvent} from 'react-native-fcm' to avoid typo`); + }; + + if (event === FCMEvent.Notification) { + return EventEmitter.addListener(event, async(data) => { + data.finish = finish; + try { await callback(data); - if(!data._finishCalled){ - data.finish(); - } - }) - } - return DeviceEventEmitter.addListener(event, callback); + } catch (err) { + console.error('Notification handler err', err); + throw err; + } + if (!data._finishCalled) { + data.finish(); + } + }); + } + return EventEmitter.addListener(event, callback); }; FCM.subscribeToTopic = (topic) => { - RNFIRMessaging.subscribeToTopic(topic); + RNFIRMessaging.subscribeToTopic(topic); }; FCM.unsubscribeFromTopic = (topic) => { - RNFIRMessaging.unsubscribeFromTopic(topic); + RNFIRMessaging.unsubscribeFromTopic(topic); }; FCM.send = (senderId, payload) => { - RNFIRMessaging.send(senderId, payload); + RNFIRMessaging.send(senderId, payload); }; export default FCM; diff --git a/ios/RNFIRMessaging.m b/ios/RNFIRMessaging.m index b7e2c581b0ee71fd000760990a77f7b6d5c0bef9..6b73beef6856ec575c058ff69cd663357195ce8a 100644 --- a/ios/RNFIRMessaging.m +++ b/ios/RNFIRMessaging.m @@ -4,7 +4,6 @@ #import @import UserNotifications; -#import #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 @@ -17,6 +16,8 @@ #endif NSString *const FCMNotificationReceived = @"FCMNotificationReceived"; +NSString *const FCMTokenRefreshed = @"FCMTokenRefreshed"; +NSString *const FCMDirectChannelConnectionChanged = @"FCMDirectChannelConnectionChanged"; @implementation RCTConvert (NSCalendarUnit) @@ -135,6 +136,10 @@ RCT_ENUM_CONVERTER(UNNotificationPresentationOptions, (@{ @synthesize bridge = _bridge; RCT_EXPORT_MODULE(); +- (NSArray *)supportedEvents { + return @[FCMNotificationReceived, FCMTokenRefreshed, FCMDirectChannelConnectionChanged]; +} + + (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull RCTRemoteNotificationCallback)completionHandler { NSMutableDictionary* data = [[NSMutableDictionary alloc] initWithDictionary: userInfo]; [data setValue:@"remote_notification" forKey:@"_notificationType"]; @@ -171,28 +176,13 @@ RCT_EXPORT_MODULE(); [[NSNotificationCenter defaultCenter] removeObserver:self]; } -- (void)setBridge:(RCTBridge *)bridge -{ - _bridge = bridge; - +- (instancetype)init { + self = [super init]; [[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]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendDataMessageFailure:) name:FIRMessagingSendErrorNotification object:nil]; @@ -201,48 +191,49 @@ RCT_EXPORT_MODULE(); 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] setRemoteMessageDelegate:self]; - [self connectToFCM]; + [[FIRMessaging messaging] setDelegate:self]; }); + return self; } -- (void)connectToFCM +RCT_EXPORT_METHOD(enableDirectChannel) { - [[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) { - if (error != nil) { - NSLog(@"Unable to connect to FCM. %@", error); - } else { - NSLog(@"Connected to FCM."); - } - }]; + [[FIRMessaging messaging] setShouldEstablishDirectChannel:@YES]; } -- (void)disconnectFCM +RCT_EXPORT_METHOD(isDirectChannelEstablished:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - [[FIRMessaging messaging] disconnect]; - NSLog(@"Disconnected from FCM"); + resolve([[FIRMessaging messaging] isDirectChannelEstablished] ? @YES: @NO); } -RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve) +RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { UILocalNotification *localUserInfo = _bridge.launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; if (localUserInfo) { resolve([[localUserInfo userInfo] copy]); - return; + } else { + resolve([_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy]); } - resolve([_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy]); } -RCT_EXPORT_METHOD(getFCMToken:(RCTPromiseResolveBlock)resolve) +RCT_EXPORT_METHOD(getAPNSToken:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - resolve([[FIRInstanceID instanceID] token]); + resolve([FIRMessaging messaging].APNSToken); } -- (void) onTokenRefresh +RCT_EXPORT_METHOD(getFCMToken:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - [self sendEventWithName:@"FCMTokenRefreshed" body:[[FIRInstanceID instanceID] token]]; + resolve([FIRMessaging messaging].FCMToken); +} + +- (void)messaging:(nonnull FIRMessaging *)messaging didRefreshRegistrationToken:(nonnull NSString *)fcmToken { + [self sendEventWithName:FCMTokenRefreshed body:fcmToken]; } RCT_EXPORT_METHOD(requestPermissions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) @@ -373,7 +364,7 @@ RCT_EXPORT_METHOD(cancelLocalNotification:(NSString*) notificationId) } } -RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTPromiseResolveBlock)resolve) +RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { if([UNUserNotificationCenter currentNotificationCenter] != nil){ [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray * _Nonnull requests) { @@ -398,7 +389,7 @@ RCT_EXPORT_METHOD(setBadgeNumber: (NSInteger*) number) [RCTSharedApplication() setApplicationIconBadgeNumber:*number]; } -RCT_EXPORT_METHOD(getBadgeNumber: (RCTPromiseResolveBlock)resolve) +RCT_EXPORT_METHOD(getBadgeNumber: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { resolve(@([RCTSharedApplication() applicationIconBadgeNumber])); } @@ -484,4 +475,10 @@ RCT_EXPORT_METHOD(finishNotificationResponse: (NSString *)completionHandlerId){ NSLog(@"sendDataMessageSuccess: %@", messageID); } +- (void)connectionStateChanged:(NSNotification *)notification +{ + [self sendEventWithName:FCMDirectChannelConnectionChanged body:[FIRMessaging messaging].isDirectChannelEstablished ? @YES: @NO]; + NSLog(@"connectionStateChanged: %@", [FIRMessaging messaging].isDirectChannelEstablished ? @"connected": @"disconnected"); +} + @end diff --git a/ios/RNFIRMessaging.xcodeproj/project.pbxproj b/ios/RNFIRMessaging.xcodeproj/project.pbxproj index 4b366c5cd5e8946c48a526905dd293eadc5b3be4..50008751b4031afd1eb89b88f03a4d70bf16637c 100644 --- a/ios/RNFIRMessaging.xcodeproj/project.pbxproj +++ b/ios/RNFIRMessaging.xcodeproj/project.pbxproj @@ -139,6 +139,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -161,6 +162,7 @@ "-Wextra", "-Wall", "-Wno-semicolon-before-method-body", + "-Wno-unused-parameter", ); }; name = Debug; @@ -183,6 +185,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -203,6 +206,7 @@ "-Wextra", "-Wall", "-Wno-semicolon-before-method-body", + "-Wno-unused-parameter", ); }; name = Release; diff --git a/ios/RNFIRMessaging.xcodeproj/xcuserdata/LLu.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/RNFIRMessaging.xcodeproj/xcuserdata/LLu.xcuserdatad/xcschemes/xcschememanagement.plist index 54a603d8ac5b1683e4f2ba069f502117aa1f998a..73056e49e31cd71f296e48160b62e0306de87b74 100644 --- a/ios/RNFIRMessaging.xcodeproj/xcuserdata/LLu.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/ios/RNFIRMessaging.xcodeproj/xcuserdata/LLu.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ RNFIRMessaging.xcscheme orderHint - 7 + 4 SuppressBuildableAutocreation