A step-by-step tutorial to help you integrate FCM, local, scheduled notification in your React Native app using react native push notification.
Make sure that you follow each step carefully! Even a single line of code or missed step will lead to endless debugging.
1) What Libraries Are Needed?
yarn add @react-native-firebase/app
yarn add @react-native-firebase/messaging
yarn add react-native-push-notification
yarn add @react-native-community/push-notification-ios
then
cd ios && pod install
2) Create a new Firebase project:
ANDROID INSTALLATION
a) Follow this link Step1
upto "Add Firebase SDKs to your app" section Link
*b) In your android/build.gradle
*You can use the default values if any value does'nt exist
ext {
googlePlayServicesVersion = "+" // default: "+"
firebaseMessagingVersion = "21.1.0" // default: "21.1.0"
// Other settings
compileSdkVersion = 30 // default: 23
buildToolsVersion = "30.0.0" // default: "23.0.1"
targetSdkVersion = 30 // default: 23
supportLibVersion = "28.0.3" // default: 23.1.1
}
c) AndroidManifest.xml
.....
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application ....>
<!-- Change the value to true to enable pop-up for in foreground on receiving remote notifications (for prevent duplicating while showing local notifications set this to false) -->
<meta-data android:name="com.dieam.reactnativepushnotification.notification_foreground"
android:value="false"/>
<!-- Change the resource name to your App's accent color - or any other color you want -->
<meta-data android:name="com.dieam.reactnativepushnotification.notification_color"
android:resource="@color/white"/> <!-- or @android:color/{name} to use a standard color -->
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
.....
Note: If you are using react-native-splash-screen follow this link link
iOS INSTALLATION
a) Follow this link Step1
upto "Register your app with Firebase" section Link
b) Follow this link Step2
**c) Update AppDelegate.h
**At the top of the file:
#import <UserNotifications/UNUserNotificationCenter.h>
Then, add the 'UNUserNotificationCenterDelegate' to protocols:
Sample (AppDelegate.h):
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
*d) Then, in your AppDelegate.m, add the following:
*
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
Then, in your AppDelegate implementation, add the following:
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
}
And then add the following lines:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
// Define UNUserNotificationCenter
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
Sample (AppDelegate.m):
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <RNSplashScreen.h>
//push
#import <Firebase.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"TestTradeAndExports"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[RNSplashScreen show];
// Define UNUserNotificationCenter
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
//push config
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
}
//Called when a notification is delivered to a foreground app.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSDictionary *userInfo = notification.request.content.userInfo;
//Foreground
NSLog(@"APP_PUSH from foreground %@", userInfo);
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:^void (UIBackgroundFetchResult result){}];
if (@available(iOS 14.0, *)) {
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBanner | UNNotificationPresentationOptionBadge);
} else {
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
}
//push
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *, id> *) options {
if ([self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]) {
return YES;
}
return [RCTLinkingManager application:app openURL:url options:options];
}
@end
USAGE in REACT NATIVE
In App.js
call "NotificationHandler" like below:
<SafeAreaProvider style={{ flex: 1, backgroundColor: Colors.dark_blue }}>
<Provider store={reduxStore}>
<PersistGate loading={null} persistor={persistor}>
<Navigation uriPrefix={prefix} {...pageProps} />
<NotificationHandler />
</PersistGate>
</Provider>
</SafeAreaProvider>
then
NotiifcationHandler.js
import { Alert, Linking, Platform } from 'react-native';
import PushNotificationIOS from '@react-native-community/push-notification-ios';
import PushNotification from 'react-native-push-notification';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import moment from 'moment';
import messaging from '@react-native-firebase/messaging';
import { STORE_DEVICE_TOKEN_ACTION } from '../store/actions/types';
import NavigationService from '../helpers/NavigationService';
import { useState } from 'react';
const NotificationHandler = () => {
const {} = useSelector(state => ({}), shallowEqual);
const dispatch = useDispatch();
const [flag, setflag] = useState(1);
const navigateFromNotificationFunc = data => {
setTimeout(
() => {
NavigationService?.navigate('NotificationScreen');
},
Platform.OS === 'ios' && !data.foreground ? 2000 : 0,
);
// switch (+id) {
// case 1:
// NavigationService.navigate('StartHeatingTime')
// break;
// default:
// break;
// }
};
// Must be outside of any component LifeCycle (such as `componentDidMount`).
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
onRegister: function (token) {
requestUserPermission(dispatch);
},
// (required) Called when a remote is received or opened, or local notification is opened
onNotification: function (notification) {
console.log('NOTIFICATION:', notification);
// alert(JSON.stringify(notification));
//if notification not clicked display popup
//if clicked navigate to screen if exist
const clicked = notification.userInteraction;
if (clicked) {
navigateFromNotificationFunc(
Platform.OS === 'ios' ? notification : notification.data,
);
} else {
if (flag === 1) {
LocalNotification(notification);
setflag(0);
}
setTimeout(() => {
setflag(1);
}, 500);
}
// (required) Called when a remote is received or opened, or local notification is opened
notification.finish(PushNotificationIOS.FetchResult.NoData);
},
// (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
onAction: function (notification) {
console.log('ACTION:', notification.action);
console.log('NOTIFICATION:', notification);
// process the action
},
// (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
// onRegistrationError: function(err) {
// console.error(err.message, err);
// },
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true,
},
popInitialNotification: true,
largeIcon: 'ic_launcher',
smallIcon: 'ic_launcher',
// Should the initial notification be popped automatically
// default: true
// senderID: '68549140594',
// requestPermissions: true
/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
* - if you are not using remote notification or do not have Firebase installed, use this:
* requestPermissions: Platform.OS === 'ios'
*/
});
return null;
};
const CancelLocalNotifications = id => {
PushNotification.cancelLocalNotification({ id: id + '' });
};
const LocalNotification = data => {
PushNotification.localNotification({
title: data?.data?.title, // (optional)
message: data?.data?.message, // (required)
playSound: true, // (optional) default: true
soundName: 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
});
};
// const LocalNotificationSchedule = data => {
// console.log('LocalNotificationSchedule', data);
// PushNotification.localNotificationSchedule({
// //... You can use all the options from localNotifications
// title: 'Hye',
// message: 'MESSAGE', // (required)
// date: new Date(Date.now() + 1000), // in n secs
// vibration: 10000, //in milliseconds
// allowWhileIdle: true,
// visibility: 'public',
// priority: 'max',
// ignoreInForeground: false,
// autoCancel: false,
// });
// };
const requestUserPermission = async dispatch => {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Notification Authorization status:', authStatus);
getAPNSToken(dispatch);
getFcmToken(dispatch);
}
// else {
// Alert.alert(
// 'Please Enable Notification',
// '',
// [
// {
// text: 'Settings',
// onPress: () => {
// Linking.openURL('app-settings:');
// },
// },
// ],
// { cancelable: false },
// );
// }
};
const getFcmToken = async dispatch => {
const fcmToken = await messaging().getToken();
if (fcmToken) {
console.log('Notification Device token ', fcmToken);
dispatch({ type: STORE_DEVICE_TOKEN_ACTION, payload: fcmToken });
} else {
console.log('Notification failed token', fcmToken);
}
};
const getAPNSToken = async () => {
const apnsToken = await messaging().getAPNSToken();
console.log('Notification Device token APNS', apnsToken);
// Alert.alert(apnsToken)
// if (apnsToken) {
// console.log('Notification Device token ', apnsToken);
// await AsyncStorage.setItem('apnsToken', apnsToken);
// } else {
// console.log('Notification failed token', apnsToken);
// }
};
export { NotificationHandler, LocalNotification };
Top comments (1)
github link?