From 3a5686c2267718a6e145afa1af6526933bf58014 Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Fri, 13 Apr 2018 14:22:17 +0100 Subject: [PATCH] [ios][notifications] Handle messaging token refreshed before bridge initialised #960 --- .../messaging/RNFirebaseMessaging.m | 45 ++++++++++++++----- lib/modules/messaging/index.js | 6 +++ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/ios/RNFirebase/messaging/RNFirebaseMessaging.m b/ios/RNFirebase/messaging/RNFirebaseMessaging.m index 81adbe01..861a5b81 100644 --- a/ios/RNFirebase/messaging/RNFirebaseMessaging.m +++ b/ios/RNFirebase/messaging/RNFirebaseMessaging.m @@ -18,6 +18,8 @@ @implementation RNFirebaseMessaging static RNFirebaseMessaging *theRNFirebaseMessaging = nil; +static bool jsReady = FALSE; +static NSString* initialToken = nil; + (nonnull instancetype)instance { return theRNFirebaseMessaging; @@ -66,7 +68,7 @@ RCT_EXPORT_MODULE() // Listen for FCM data messages that arrive as a remote notification - (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo { NSDictionary *message = [self parseUserInfo:userInfo]; - [RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message]; + [self sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message]; } // ******************************************************* @@ -82,13 +84,13 @@ RCT_EXPORT_MODULE() // Listen for FCM tokens - (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken { NSLog(@"Received new FCM token: %@", fcmToken); - [RNFirebaseUtil sendJSEvent:self name:MESSAGING_TOKEN_REFRESHED body:fcmToken]; + [self sendJSEvent:self name:MESSAGING_TOKEN_REFRESHED body:fcmToken]; } // Listen for data messages in the foreground - (void)applicationReceivedRemoteMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage { NSDictionary *message = [self parseFIRMessagingRemoteMessage:remoteMessage]; - [RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message]; + [self sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message]; } // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground. @@ -96,7 +98,7 @@ RCT_EXPORT_MODULE() - (void)messaging:(nonnull FIRMessaging *)messaging didReceiveMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage { NSDictionary *message = [self parseFIRMessagingRemoteMessage:remoteMessage]; - [RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message]; + [self sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message]; } // ******************************************************* @@ -120,11 +122,11 @@ RCT_EXPORT_METHOD(requestPermission:(RCTPromiseResolveBlock)resolve rejecter:(RC [RCTSharedApplication() registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:types categories:nil]]; // We set the promise for usage by the AppDelegate callback which listens // for the result of the permission request - _permissionRejecter = reject; - _permissionResolver = resolve; + self.permissionRejecter = reject; + self.permissionResolver = resolve; }); } else { - #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 + if (@available(iOS 10.0, *)) { // For iOS 10 display notification (sent via APNS) UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { @@ -134,7 +136,7 @@ RCT_EXPORT_METHOD(requestPermission:(RCTPromiseResolveBlock)resolve rejecter:(RC reject(@"messaging/permission_error", @"Failed to grant permission", error); } }]; - #endif + } } dispatch_async(dispatch_get_main_queue(), ^{ @@ -149,11 +151,11 @@ RCT_EXPORT_METHOD(hasPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPro resolve(@([RCTSharedApplication() currentUserNotificationSettings].types != UIUserNotificationTypeNone)); }); } else { - #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 + if (@available(iOS 10.0, *)) { [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { resolve(@(settings.alertSetting == UNNotificationSettingEnabled)); }]; - #endif + } } } @@ -189,8 +191,31 @@ RCT_EXPORT_METHOD(unsubscribeFromTopic: (NSString*) topic resolve(nil); } +RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { + jsReady = TRUE; + resolve(nil); + if (initialToken) { + [self sendJSEvent:self name:MESSAGING_TOKEN_REFRESHED body:initialToken]; + } +} + // ** Start internals ** +// Because of the time delay between the app starting and the bridge being initialised +// we catch any events that are received before the JS is ready to receive them +- (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(id)body { + if (emitter.bridge && jsReady) { + [RNFirebaseUtil sendJSEvent:emitter name:name body:body]; + } else { + if ([name isEqualToString:MESSAGING_TOKEN_REFRESHED]) { + initialToken = body; + } else { + // TODO: Is this even possible? + NSLog(@"Received Remote Message before the bridge is ready"); + } + } +} + - (NSDictionary*)parseFIRMessagingRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage { NSDictionary *appData = remoteMessage.appData; diff --git a/lib/modules/messaging/index.js b/lib/modules/messaging/index.js index 595058e2..cf163087 100644 --- a/lib/modules/messaging/index.js +++ b/lib/modules/messaging/index.js @@ -2,6 +2,7 @@ * @flow * Messaging (FCM) representation wrapper */ +import { Platform } from 'react-native'; import { SharedEventEmitter } from '../../utils/events'; import INTERNALS from '../../utils/internals'; import { getLogger } from '../../utils/log'; @@ -63,6 +64,11 @@ export default class Messaging extends ModuleBase { SharedEventEmitter.emit('onTokenRefresh', token); } ); + + // Tell the native module that we're ready to receive events + if (Platform.OS === 'ios') { + getNativeModule(this).jsInitialised(); + } } getToken(): Promise {