React Native Integrating Push Notifications with firebase and react native push notification with navigate to screen

React Native Push Notifications firebase navigate screen react-native-firebase react-native-push-notification

In this post, we’ll learn how to set up push notifications in React Native apps using Firebase. We’ll send notifications using the Firebase console and receive them in the app. We will also learn how to handle push notifications in your React Native apps. By handling, I mean how to access the data sent via the notification inside your app, and wake your app up if it is asleep or closed. 

Because all this can get really long, I’ll limit the discussion to Android apps alone. I will post another blog for a push in iOS apps in React Native. (Really, the major difference is in setting up the push certificates for the iOS app, that’s all)

Structure

I will go ahead in a step-by-step fashion so you can follow easily.

  1. Create a Firebase project and find Push options
  2. Create a basic React Native app
  3. Install Push notification dependency
  4. Build the app on Android
  5. Send notifications from the Firebase console
  6. Handle different types of Push notifications in your app

1. Create a Firebase project and find Push options

Go to Firebase and create your first project (or use an existing one). Your console should look like this

 

Your Firebase projects all in one place

Note — It’s really easy to create a Firebase project, but if you still face any issue, follow step 1–4 of this blog

Click on your project and you’ll enter the project’s dashboard. Look for Cloud Messaging tab. This is where the magic will happen !

 

Cloud messaging section of Firebase console — You can send push notifications from here

Push Notifications Settings

Firebase console also contains push notifications settings for the web, android, and iOS. Here you can find your sender_id, upload iOS push certificates, etc. For setting up options, you’ll first have to create an Android app in the Firebase console.

 

Add a new Android app in Firebase

During the process, it will ask you to enter the app’s package name and provide google-services.json. Make sure you keep a unique package name/bundle ID for your app. (If we create a new project called “HelloWorld” using react-native CLI, by default package name for the android project will be “com.RNPushNotification” and the default bundle identifier for iOS app will be “org.reactjs.native.example.RNPushNotification”., don’t use the default package name)

 

Download google-services.json

2. Create a basic React Native app

First, make sure you have all pre-requisites to create a react-native app as per the official documentation.

Create a blank react-native app (Replace myApp with your own name)

$ react-native init myApp

This will create a basic React-native app that you can run on a device or simulator. (either Android or iOS)

Let’s run the app on Android using 

$ react-native run-android

3. Install Push notification dependency

There are two major dependency/plugin you can use to implement push notifications

  1. react-native-push-notification
  2. @react-native-firebase/app
  3. @react-native-firebase/messaging
  4. @react-navigation/native
  5. @react-navigation/stack
  6. react-native-safe-area-context

react-native-firebase is a major plugin that can implement almost all Firebase functionalities in react-native. But for this tutorial, we’ll use the react-native-push-notification plugin, which is made only for Push Notification purposes. 

Install the dependency using

$ npm install --save react-native-push-notification @react-native-firebase/app @react-native-firebase/messaging / yarn add react-native-push-notification @react-native-firebase/app @react-native-firebase/messaging

1. Edit android/build.gradle

In your android/build.gradle , edit the googlePlayServicesVersion and firebaseVersion . Following are the values in my (working) setup

  ext {
     buildToolsVersion = "30.0.2"
     minSdkVersion = 27
     compileSdkVersion = 31
     targetSdkVersion = 31
     ndkVersion = "26.4.7075529"
     googlePlayServicesVersion = "17.0.0"
     firebaseMessagingVersion = '21.1.0'
     kotlin_version = '1.2.10'
 }
 dependencies {
     classpath("com.android.tools.build:gradle:4.1.1")
     classpath 'com.google.gms:google-services:4.3.10'
     // NOTE: Do not place your application dependencies here; they belong
     // in the individual module build.gradle files
 }

In your android/app/build.gradle , add apply plugin

apply plugin: 'com.google.gms.google-services'

defaultConfig {
    applicationId "com.rnpushnotification"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

implementation 'androidx.multidex:multidex:2.0.1'

2. Edit AndroidManifest.xml

In your AndroidManifest.xml , add following before <application 

<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application .......>
< meta - data android: name = "com.dieam.reactnativepushnotification.notification_foreground"
android: value = "true" / >

    <meta - data android: name = "com.dieam.reactnativepushnotification.notification_color"
android: resource = "@color/white" / >
    <meta - data android: name = "com.dieam.reactnativepushnotification.notification_icon"
android: resource = "@mipmap/ic_launcher" / >

    <meta - data android: name = "com.google.firebase.messaging.default_notification_icon"
android: resource = "@mipmap/ic_launcher" / >

    <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>
... </application>

Be careful while copy-pasting these values. Don’t disturb other values in the XML file. 

3. Create a Color resource

In step 3.2 above, we called for a white color as the notification_color. If that does not exist in your project, create it. You can also change this to any color you want. Create the android/app/src/res/values/colors.xml file if it does not exist

<resources>
<color name="white">#FFF</color>
</resources>

4. Project Folder Structure

android 
ios 
node_modules 
src 
     notification
         FCMService.js
         LocalNotificationService.js
     routes
         index.js
     screens 
         Home 
             index.js
        List
            index.js 
     RootNavigation.js
app.json 
App.js 
babel.config.js 
index.js 
metro.config.js 
package.json
  • create a screen folder and add folder and file like project Folder Structure and add code

Home.js

import React from 'react'
import {
    View,
    Text,
    SafeAreaView,
    Button
} from 'react-native'

const Home = ({
    navigation
}) => {
    console.log("navigation", navigation)
    return ( <
        SafeAreaView style = {
            {
                flex: 1,
                justifyContent: 'center',
            }
        } >
        <
        View style = {
            {
                justifyContent: 'center',
                alignItems: 'center',
                alignContent: 'center'
            }
        } >
        <
        Text > Home Page < /Text>  <
        Button title = "list page"
        onPress = {
            () => navigation.navigate("List")
        }
        /> <
        /View> <
        /SafeAreaView>
    )
}

export default Home

List.js

import React from 'react'
import {
    View,
    Text,
    SafeAreaView,
    Button
} from 'react-native'

const List = ({
    navigation
}) => {
    console.log("navigation", navigation)
    return ( <
        SafeAreaView style = {
            {
                flex: 1,
                justifyContent: 'center',
            }
        } >
        <
        View style = {
            {
                justifyContent: 'center',
                alignItems: 'center',
                alignContent: 'center'
            }
        } >
        <
        Text > Home Page < /Text>  <
        Button title = "Go To Home"
        onPress = {
            () => navigation.navigate("Home")
        }
        /> <
        /View> <
        /SafeAreaView>
    )
}

export default List
  • create a routes folder create index.js file in routes folder routes/index.js
import React from 'react';

import {
    createStackNavigator
} from '@react-navigation/stack';
import Home from '../screen/Home';
import List from '../screen/List';

const Stack = createStackNavigator();
const headerOptions = {
    headerShown: false
}
const PageRoutes = () => ( <
    Stack.Navigator screenOptions = {
        headerOptions
    } >
    <
    Stack.Screen name = "Home"
    component = {
        Home
    }
    /> <
    Stack.Screen name = "List"
    component = {
        List
    }
    /> <
    /Stack.Navigator>
);

export default PageRoutes;
  • create a notification folder and add/create file like project Folder Structure and add code

FCMService.js

import messaging from '@react-native-firebase/messaging';
import {
    Platform
} from 'react-native';
import {
    localNotificationService
} from './LocalNotificationService';

class FCMService {
    register = (onRegister, onNotification, onOpenNotification) => {
        this.checkPermission(onRegister);
        this.createNotificationListeners(onRegister, onNotification, onOpenNotification);
    }

    registerAppWithFCM = async () => {
        if (Platform.OS === 'ios') {
            await messaging().registerDeviceForRemoteMessages();
            await messaging().setAutoInitEnabled();
        }
    }

    checkPermission = (onRegister) => {
        messaging().hasPermission()
            .then(enabled => {
                if (enabled) {
                    // User has permission
                    this.getToken(onRegister);
                } else {
                    // User don't have permission
                    this.requestPermission(onRegister);
                }
            }).catch(error => {
                console.log("[FCMService] Permission Rejected", error);
            })
    }

    getToken = (onRegister) => {
        messaging().getToken()
            .then(fcmToken => {
                if (fcmToken) {
                    onRegister(fcmToken)
                } else {
                    console.log("[FCMService] User does not have a devices token")
                }
            }).catch(error => {
                console.log("[FCMService] getToken Rejected", error);
            })
    }

    requestPermission = (onRegister) => {
        messaging().requestPermission()
            .then(() => {
                this.getToken(onRegister);
            }).catch(error => {
                console.log("[FCMService] Request Permission Rejected", error);
            })
    }

    deleteToken = () => {
        console.log("[FCMService] Delete Token");
        messaging().deleteToken()
            .catch(error => {
                console.log("[FCMService] Delete Token Error", error);
            })
    }

    createNotificationListeners = (onRegister, onNotification, onOpenNotification) => {

        // When Application Running on Background
        messaging().onNotificationOpenedApp(remoteMessage => {
            console.log("[FCMService] OnNotificationOpenedApp getInitialNotification", remoteMessage);
            if (remoteMessage) {
                const notification = remoteMessage;
                onOpenNotification(notification);
            }
        });

        //When Application open from quit state
        messaging().getInitialNotification()
            .then(remoteMessage => {
                console.log("[FCMService] getInitialNotification getInitialNotification", remoteMessage);
                if (remoteMessage) {
                    const notification = remoteMessage;
                    localNotificationService.cancelAllLocalNotifications();
                    onOpenNotification(notification);
                }
            });

        //Forground state message
        this.messageListener = messaging().onMessage(async remoteMessage => {
            console.log("[FCMService] A new FCm message arrived", remoteMessage);
            if (remoteMessage) {
                let notification = null;
                if (Platform.OS === 'ios') {
                    notification = remoteMessage.data
                } else {
                    notification = remoteMessage
                }

                onNotification(notification);
            }
        });

        // Triggered when have new Token
        messaging().onTokenRefresh(fcmToken => {
            console.log("[FCMService] New token refresh", fcmToken);
            onRegister(fcmToken);
        });
    }

    unRegister = () => {
        this.messageListener();
    }

    stopAlarmRing = async () => {
        if (Platform.OS != 'ios') {
            await messaging().stopAlarmRing();
            console.log('sdfghjkldfgh', "stopAlarmRing");
        }
    }
}
export const fcmService = new FCMService()

LocalNotificationService.js

import PushNotification from "react-native-push-notification"

class LocalNotificationService {
    configure = (onOpenNotification) => {
        PushNotification.configure({
            onRegister: function(token) {
                console.log("[LocalNotificationService] onRegister:", token);
            },
            onNotification: function(notification) {
                console.log("[LocalNotificationService] onNotification:", notification);
                if (!notification?.data) {
                    return
                }
                notification.userInteraction = true;
                onOpenNotification(notification);
            },
            // IOS ONLY (optional): default: all - Permissions to register.
            permissions: {
                alert: true,
                badge: true,
                sound: true,
            },

            // Should the initial notification be popped automatically
            // default: true
            popInitialNotification: 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'
             */
            requestPermissions: true,
        })
    }

    unregister = () => {
        PushNotification.unregister();
    }

    showNotification = (id, title, message, data = {}, options = {}) => {
        PushNotification.localNotification({
            /* Android Only Properties */
            ...this.buildAndroidNotification(id, title, message, data, options),
            title: title || "",
            message: message || "",
            playSound: options.playSound || false,
            soundName: options.soundName || 'default',
            userInteraction: false, // BOOLEAN : If notification was opened by the user from notification
            channelId: "32",
            badge: true,
        });
    }

    buildAndroidNotification = (id, title, message, data = {}, options = {}) => {
        return {
            id: id,
            autoCancel: true,
            largeIcon: options.largeIcon || "ic_launcher",
            smallIcon: options.smallIcon || "ic_notification",
            bigText: message || '',
            subText: title || '',
            vibrate: options.vibrate || true,
            vibration: options.vibration || 300,
            priority: options.priority || 'high',
            importance: options.importance || 'high',
            data: data,
        }
    }

    cancelAllLocalNotifications = () => {
        PushNotification.cancelAllLocalNotifications();
    }

    removeDeliveredNotificationByID = (notificationId) => {
        console.log("[LocalNotificationService] removeDeliveredNotificationByID:", notificationId);
        PushNotification.cancelLocalNotifications({
            id: `${notificationId}`
        })
    }

    // applicationBadge = () => {
    //     // PushNotification.setApplicationIconBadgeNumber(2);
    //     // const ShortcutBadger = NativeModules.ShortcutBadger;
    //     // let count = 1;
    //     // ShortcutBadger.applyCount(count);
    // }
}

export const localNotificationService = new LocalNotificationService();
  • create a RootNavigation.js file in the src folder and add code
import * as React from 'react';

export const navigationRef = React.createRef();

export function navigate(name, params) {
    navigationRef.current?.navigate(name, params);
}
  • open an App.js file add code
import React, {
    useEffect
} from 'react';
import {
    NavigationContainer
} from '@react-navigation/native';
import PageRoutes from './src/routes';
import {
    fcmService
} from './src/notification/FCMService';
import {
    localNotificationService
} from './src/notification/LocalNotificationService';
import {
    navigationRef,
    navigate
} from './src/RootNavigation';

const App = () => {
    useEffect(() => {
        fcmService.registerAppWithFCM();
        fcmService.register(onRegister, onNotification, onOpenNotification);
        localNotificationService.configure(onOpenNotification)
    }, []);


    const onRegister = (token) => {
        console.log("[App] Token", token);
    }

    const onNotification = (notify) => {
        // console.log("[App] onNotification", notify);
        const options = {
            soundName: 'default',
            playSound: true,
            largeIcon: "ic_launcher", // (optional) default: "ic_launcher"
            smallIcon: "ic_launcher", // (optional) default:  "ic_notification" with fallback for "ic_launcher"
        }

        localNotificationService.showNotification(
            0,
            notify.notification.title,
            notify.notification.body,
            notify,
            options,
        )
    }

    const onOpenNotification = async (notify) => {
        console.log('notify', notify);
        if (notify && notify.data && notify.data.page == "list") {
            navigate('List', notify.data);
        } else if (notify && notify.data && notify.data.page == "home") {
            navigate('Home', notify.data);
        }
    }

    return ( <
        NavigationContainer ref = {
            navigationRef
        } >
        <
        PageRoutes / >
        <
        /NavigationContainer>
    );
};

export default App;

Hope this tutorial saves your time and makes FCM integration easy in react native. If it helps you in any way, don’t forget to love! Thanks :)

About the author
Code solution

info@codesolution.co.in

Discussion
  • 0 comments

Add comment To Login
Add comment