From 4d4bcde8388a1af38c62b1896e25cd65d9f926d3 Mon Sep 17 00:00:00 2001 From: seblau Date: Thu, 28 Dec 2017 11:42:40 +0100 Subject: [PATCH] upgrade to react-native-fcm 10.0.3 + support show_in_foreground for android --- shoutem.firebase/app/app.js | 69 ++++++++++++++----- shoutem.firebase/app/firebase.android.js | 7 -- shoutem.firebase/app/firebase.ios.js | 2 - shoutem.firebase/app/middleware.js | 2 +- shoutem.firebase/app/package.json | 2 +- .../scripts/android/copy_custom_manifest.js | 15 ++-- .../app/scripts/ios/add_native_code_mods.js | 32 ++++----- 7 files changed, 75 insertions(+), 54 deletions(-) delete mode 100644 shoutem.firebase/app/firebase.android.js delete mode 100644 shoutem.firebase/app/firebase.ios.js diff --git a/shoutem.firebase/app/app.js b/shoutem.firebase/app/app.js index df69e6b6..83b02d23 100644 --- a/shoutem.firebase/app/app.js +++ b/shoutem.firebase/app/app.js @@ -1,4 +1,5 @@ -import FCM from 'react-native-fcm'; +import { Platform } from 'react-native'; +import FCM, { FCMEvent } from 'react-native-fcm'; import { isProduction } from 'shoutem.application'; @@ -16,11 +17,33 @@ function appDidMount(app) { const store = app.getStore(); const { dispatch } = store; - - const dispatchNotificationAction = (receivedNotification) => { - const { body, title, action, opened_from_tray } = receivedNotification; - const notification = { body, openedFromTray: opened_from_tray, title }; - + + const dispatchNotificationAction = (receivedNotification) => { + if (receivedNotification.fcm) { + var { fcm, action, opened_from_tray, show_in_foreground } = receivedNotification; + var notification = { body: fcm.body, openedFromTray: opened_from_tray, title: fcm.title }; + + if (show_in_foreground) { + FCM.presentLocalNotification({ + title: notification.title, + body: notification.body, + sound: "default", + priority: "high", + click_action: action, + ticker: notification.body, + auto_cancel: true, + vibrate: 300, + ongoing: false, + show_in_foreground: true + }); + } + } else if (receivedNotification.aps) { + var { aps, action, opened_from_tray } = receivedNotification; + var notification = { body: aps.alert, openedFromTray: opened_from_tray, title: receivedNotification['google.c.a.c_l'] }; + } else { + return; + } + if (action) { try { const actionObject = JSON.parse(action); @@ -33,21 +56,35 @@ function appDidMount(app) { dispatch(notificationReceived(notification)); }; - FCM.getFCMToken().then((token) => { - handleReceivedToken(token, dispatch); + // this shall be called regardless of app state: running, background or not running. Won't be called when app is killed by user in iOS + FCM.on(FCMEvent.Notification, async (notif) => { + if (notif) { + dispatchNotificationAction({ ...notif }); + + // iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application. + if (Platform.OS === 'ios') { + notif.finish(); + } + } }); - - FCM.on('notification', dispatchNotificationAction); - - FCM.getInitialNotification().then((notification) => { - if (notification) { - dispatchNotificationAction({ ...notification, opened_from_tray: true }); - } + + FCM.on(FCMEvent.RefreshToken, (token) => { + // fcm token may not be available on first load, catch it here + handleReceivedToken(token, dispatch); }); - FCM.on('refreshToken', (token) => { + FCM.getFCMToken().then((token) => { handleReceivedToken(token, dispatch); }); + + // initial notification contains the notification that launchs the app. If user launchs app by clicking banner, the banner notification info will be here rather than through FCM.on event + // sometimes Android kills activity when app goes to background, and when resume it broadcasts notification before JS is run. You can use FCM.getInitialNotification() to capture those missed events. + // initial notification will be triggered all the time even when open app by icon so send some action identifier when you send notification + FCM.getInitialNotification().then(notif => { + if (notif) { + dispatchNotificationAction({ ...notif }); + } + }); } export { diff --git a/shoutem.firebase/app/firebase.android.js b/shoutem.firebase/app/firebase.android.js deleted file mode 100644 index 2cc3f1d1..00000000 --- a/shoutem.firebase/app/firebase.android.js +++ /dev/null @@ -1,7 +0,0 @@ -import firebase from 'react-native-fcm'; - -export default { - ...firebase, - requestPermissions: console.log.bind(null, 'Request permissions not available on Android'), - setBadgeNumber: console.log.bind(null, 'Setting a badge number not available on Android'), -}; diff --git a/shoutem.firebase/app/firebase.ios.js b/shoutem.firebase/app/firebase.ios.js deleted file mode 100644 index 7e3f1bd7..00000000 --- a/shoutem.firebase/app/firebase.ios.js +++ /dev/null @@ -1,2 +0,0 @@ -import firebase from 'react-native-fcm'; -export default firebase; diff --git a/shoutem.firebase/app/middleware.js b/shoutem.firebase/app/middleware.js index fec9a212..43047ead 100644 --- a/shoutem.firebase/app/middleware.js +++ b/shoutem.firebase/app/middleware.js @@ -5,7 +5,7 @@ import { } from 'shoutem.push-notifications'; import { isProduction } from 'shoutem.application'; -import FCM from './firebase'; +import FCM from 'react-native-fcm'; // eslint-disable-next-line no-unused-vars const requestPermissions = store => next => action => { diff --git a/shoutem.firebase/app/package.json b/shoutem.firebase/app/package.json index a270c284..cdd17b29 100644 --- a/shoutem.firebase/app/package.json +++ b/shoutem.firebase/app/package.json @@ -4,7 +4,7 @@ "description": "Firebase SDK bridge", "dependencies": { "request": "2.79.0", - "react-native-fcm": "5.0.0", + "react-native-fcm": "10.0.3", "xcode": "0.8.9", "lodash": "^4.17.2", "urijs": "1.18.5" diff --git a/shoutem.firebase/app/scripts/android/copy_custom_manifest.js b/shoutem.firebase/app/scripts/android/copy_custom_manifest.js index 0219b670..79c267e2 100644 --- a/shoutem.firebase/app/scripts/android/copy_custom_manifest.js +++ b/shoutem.firebase/app/scripts/android/copy_custom_manifest.js @@ -25,7 +25,7 @@ permissions.forEach(permission => { // add firebase services const services = ` - + @@ -36,14 +36,15 @@ const services = ` + - - - - - - + + + + + + `; diff --git a/shoutem.firebase/app/scripts/ios/add_native_code_mods.js b/shoutem.firebase/app/scripts/ios/add_native_code_mods.js index dfa153cb..a47b5348 100644 --- a/shoutem.firebase/app/scripts/ios/add_native_code_mods.js +++ b/shoutem.firebase/app/scripts/ios/add_native_code_mods.js @@ -45,9 +45,7 @@ if (~appDelegateContents.indexOf(firHeaderImportStatement)) { // 4. Add to applicationDidFinishLaunchingWithOptions const notificationCenterInitializationPatch = ` [FIRApp configure]; - #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; - #endif `; if (~appDelegateContents.indexOf(notificationCenterInitializationPatch)) { @@ -60,34 +58,29 @@ if (~appDelegateContents.indexOf(notificationCenterInitializationPatch)) { // 5. Add methods to app delegate body const addMethodsPatch = ` -#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { - [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:notification.request.content.userInfo]; - if([[notification.request.content.userInfo valueForKey:@"show_in_foreground"] isEqual:@YES]){ - completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound); - }else{ - completionHandler(UNNotificationPresentationOptionNone); - } - + [RNFIRMessaging willPresentNotification:notification withCompletionHandler:completionHandler]; } -- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler +#if defined(__IPHONE_11_0) +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { - NSDictionary* userInfo = [[NSMutableDictionary alloc] initWithDictionary: response.notification.request.content.userInfo]; - [userInfo setValue:@YES forKey:@"opened_from_tray"]; - [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:userInfo]; + [RNFIRMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; } #else -//You can skip this method if you don't want to use local notification --(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { - [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self + userInfo:notification.userInfo]; +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler +{ + [RNFIRMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; } #endif +-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { + [RNFIRMessaging didReceiveLocalNotification:notification]; +} + - (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{ - [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:userInfo]; - completionHandler(UIBackgroundFetchResultNoData); + [RNFIRMessaging didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } `; @@ -101,4 +94,3 @@ if (~appDelegateContents.indexOf(addMethodsPatch)) { fs.writeFileSync(appDelegateHeaderPath, appDelegateHeaderContents); fs.writeFileSync(appDelegatePath, appDelegateContents); -