react native push notifications

React native push notifications using react native firebase

Overview

Push notifications are undoubtedly one of the vital parts of any mobile applications. They provide greater attention and improves overall interaction. Here in this post, we are going to implement the react-native push notifications in a react-native project.

We’ll use the technologies like react native firebase, firebase cloud messaging and node JS.

Being a react native developer, we have the freedom of maintaining one single codebase for multiple platforms. And the application development is much easier with pre-built components. However, when it comes to the implementation of native features it definitely has limitations.

We, developers, are already aware of the un-predictable changes SDK/Package teams releases which are used to develop the applications. So, while developing the application, a developer must think from a broader mindset to provide support for each device.

Here we’ll discuss everything you need to know to implement the push notifications in react native application. We’ll cover topics like creating a react native project, creating and setting up a firebase project, creating a backend firebase admin in NodeJS, Configuring push notifications for Android, Notification payload types and their importance, Notification click handlers, notifications events, custom notification sound etc.

Creating a react native project

Typically there are two ways to create a project to react-native. We can either use the bare react native project or start with EXPO SDK. If you don’t know the differences between these two make sure you check out this article first.

Read: Expo managed workflow vs Bare workflow – React native

Basically, when I started with react native I found that it’s easy to create a project with EXPO SDK’s managed workflow. Expo provides feature-rich APIs to implement most of your business requirements. However, when I moved ahead I found it’s hard to maintain and keep up with expo SDK. The reason for that problem is the release APK size. It usually is more than 25MB for a simple “Hello world” application. I know it’s too much for a simple application.

So, we have the other option of continuing with the bare react native project. Which again I found it’s difficult to configure for a much-required react-native package react-native-gesture-handler. The solution to this problem is to start a project with expo bare workflow. In the bare expo project they have pre configured the gesture handler package.

Create the project using,

$ expo init push-notifications

You’ll be asked to chose which workflow is suitable for you start with. Make sure you chose the expo bare workflow and get started.

Configuring for react native push notifications

We have three packages to work with firebase and push notifications. Honestly, I tried all of them and found that the react-native-firebase library has everything you need to implement react native push notifications. To install and configure react-native-firebase in your application follow the steps given below.

Disclaimer: Few of the codes are directly taken from the official documentation and I do not own the same.

Let’s start by installing react-native firebase in our project.

$ yarn add @react-native-firebase/app

For the sake of this post, I’ll be configuring everything for the android devices. However, apart from the android configuration, everything else will be the same. To start with, first, add the google-services plugin as a dependency to the /android/build.gradle file.

buildscript {
  dependencies {
    // ... other dependencies
    classpath 'com.google.gms:google-services:4.3.4'
    // Add me --- /\
  }
}

After the adding the dependency we need to execute the plugin by adding the following inside your /android/app/build.gradle file.

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services' // <- Add this line

Next we’ll add the cloud-messaging functionality to the react native project. In order to add cloud messaging install the package as given below.

$ yarn add @react-native-firebase/messaging

Once you are added firebase to the project we need to add few lines to the Manifest file. Add the following broadcast listener to the /android/app/src/main/AndroidManifest.xml file inside the <application> tag.

<receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver"></receiver>
<receiver android:enabled="true" android:exported="true" android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver"></receiver>

Creating a firebase project

Firebase is a cloud service provided by Google to facilitate the cloud requirements of a project. Although firebase has a lot of services, we are much more interested in the firebase cloud messaging service.

Create firebase project

To start, create a firebase project and add the android app to the project. Here, make sure you are providing the package name exactly the same as given in the AndroidManifest.xml file. If not given accurately the push notifications will not work.

In most cases, you might probably have a firebase project. And if the react-native package name is different, modify the package name of the application using the following guide.

Add android app to the project

After creating the android project, firebase will provide you with a google-services.json file which you have to place inside the /android/app directory. As of now, we have fully configured the react native project to receive the push notifications from firebase.

Configure backend admin server in Node-JS

If you are working for a company or as a freelancer you will not be sending any message directly from FCM. Let’s assume that you have different types of users and you need to send different types of messages to the devices. In such scenarios, you need to have a backend server that can handle the heavy tasks for firebase.

The Firebase team is already developed a well-maintained firebase admin package in many languages. Here in this application, we are going to use the firebase admin SDK written for NodeJS as they are easy to maintain and configure.

To start with backend we are going to create an http server using expressJS. Create the project using the command given below.

$ mkdir backend
$ cd backend
$ yarn add express
$ touch index.js

Once you are created the project and installed the express we can create our server by adding the following content to the index.js file.

//Index.js 

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Express app listening at http://localhost:${port}`)
})

To add firebase admin to the project we need to install the package as given below.

Adding firebase admin to the project

$ yarn add firebase-admin

Firebase admin is a package written to interact with the firebase from your backend servers. In order to work with firebase admin, we need to have the following things ready in our hand.

  1. A Firebase android project
  2. A service account to communicate with Firebase
  3. A configuration file with your service account’s credentials

As we have created a Firebase project we can continue adding the service account details to the backend project. To add the service account details we need to generate a private key in JSON format which is used to communicate between firebase APIs using the service account. To create the key follow the steps below.

  1. Firebase console, click Settings > Service Accounts.
  2. Click Generate a New Private Key, and confirm by clicking Generate Key.
  3. Securely store the JSON file containing the key in your system.
Generate a private key

Once created the private key we can add this to our project using any of the two methods firebase allows. Which are basically setting up an environment variable each time you start the server or set the path directly inside your backend file.

For the scope of this post, and a much more convenient way, we are going to specify the file in the project itself. To do that first add the firebase admin SDK to the project.

//index.js

const express = require('express');
const admin = require('firebase-admin');

Once you added the package specify the private key in the file as given below.

//index.js

const serviceAccount = require("./serviceAccount.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: 'https://<DATABASE_NAME>.firebaseio.com'
});

Therefore we have successfully configured firebase admin for NodeJS backend. Now we need to create an endpoint in the express server to send a push notification to the react-native application.

Configure route and send notifications

In order to understand the use case much better, we are going to assume that you have two different applications in which one of the applications used by the customer and the other one is by managers.

The customers register for your services and the managers need to provide them with a timely update on the services via push notifications. In order to send push notifications to the target devices, we need to create an endpoint which we’ll use to send cloud-based react-native push notifications. What we are doing that whenever a user registers to the service we are storing their device token in the backend application.

//Index.js

let tokens = [];

app.post('/register',(req,res) => {
    let { username, password, token } = req.body;
    verifyLogin(username, password)
    .then(() => {
      tokens.push(token);
    })
    .then(() => {
      res.send({
        status: "Device registered";
      })
    })
})

In most cases, you’ll be storing the tokens inside a database or firebase cloud storage. To send cloud-based push notifications to the registered tokens we can create the function as given below.

//Index.js

function sendNotifications() {
    let tokens = ["token1", "token2", "toekn3"];
    var message = {
        notification: {
            title: "New message received",
            body: "Messaged received from user"
        },
        toekns: tokens
    };

    admin.messaging().send(message)
        .then((response) => {
            console.log('Successfully delivered notification:', response);
        })
        .catch((error) => {
            console.log('Error sending notification:', error);
        });
}

As of now, we are ready to register the device from the react native application and receive push notifications.

Receive react native push notifications

So, we have configured the backend to send notifications to the target devices using registered tokens. To register the tokens we need to generate them and pass them to the backend server. To do so, create a function in your react native login.js file and register the device for push notifications.

//Login.js

import React, { PureComponent } from 'react';
import { TextInput,View,Text,Button } from 'react-native';
import messaging from "@react-native-firebase/messaging";

class Login extends PureCompoent {
  constructor(props) {
    super(props);
    this.state = {
      username: "",
      password: ""
    }
    this.login = this.login.bind(this);
    this.registerToken = this.registerToken.bind(this);
  }

  login(token) {
    let { username, password } = this.state;
    let request = await fetch(`http://localhost:4000/register`,{
      method:'POST',
      body: JSON.stringify({
        username: username,
        password: password,
        token: token
      })
    });
    let response = await request.json();
    if(response){
      console.log("Login successful and device registered");
    }
  }

   //register the user's firebase token
   registerToken() {
    messaging().getToken().then(token => {
      this.login(token);
    })
  }

  render() {
    return (
      <View>
        <TextInput
          onChangeText={(text) => this.setState({ username: text })}
          placeholder="Enter username"
        />
        <TextInput
          onChangeText={(text) => this.setState({ password: text })}
          placeholder="Enter password"
        />
        <Button
          onPress={this.registerToken}
          title="login"
        />
      </View>
    )
  }
}

This is an example to handle login in a react native application. In real-time applications, it’s possible to have separate API endpoints to handle login and device registrations.

Now, the device is successfully registered and can receive a push notification from the backend express server using firebase admin and cloud messaging. The server can trigger the SendNotifications function to send push notifications to the registered devices.

Notification payload and priority

It’s possible to specify the notification payload type from the backend. The reason because is that usual notification can’t be used to transfer data payloads from the backend to the client device. Also, data payloads can be used to deliver silent push notifications which will not disturb the user.

As we are using react native firebase package to deliver push notifications, the library does not show any heads up notification to the user if in case the payload is a data object. In most situations, the device does not show any notifications in the system tray if you are using data payloads.

So, to transfer custom data and show heads us notification in the system tray we need to specify the priority in the backend server. To receive the head us notification we can use,

admin.messaging().sendToDevice(
  [], // device firebase tokens
  {
    data: {
      message: JSON.stringify(owner),
      time: JSON.stringify(user),
    },
  },
  {
    //iOS heads up notification
    contentAvailable: true,
    //Android heads up notification
    priority: 'high',
  },
);

Configure custom notification sound

As of now, we have learned the implementation of react-native push notifications using firebase admin and firebase cloud messaging services. In order to maximize the user’s attention, we can configure the custom sound to be played while receiving push notifications.

For react native applications I found it’s challenging to configure custom audio files for the push notifications. However, if you are using the react-native push notifications library they have added custom audio support for the local notifications. But in our use case, we have a remote message which has to be configured using custom audio.

To add the custom notification sound place your audio file inside /android/app/src/main/res/raw with the file name you like to put but make sure it does not contain space. Once you added the file we can configure the MainActicity.java file which resides inside the /android/app/src/main/java folder.

Open the file and add the following content to the onCreate function.

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.media.AudioAttributes;
import android.content.ContentResolver;
import android.net.Uri;
import androidx.core.app.NotificationCompat;
 
//Channel management works api version > 26
 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
  NotificationChannel notificationChannel = new NotificationChannel("channelname", "packagename", NotificationManager.IMPORTANCE_HIGH);
  notificationChannel.setShowBadge(true);
  notificationChannel.setDescription("");
  AudioAttributes att = new AudioAttributes.Builder()
      .setUsage(AudioAttributes.USAGE_NOTIFICATION)
      .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
      .build();
  notificationChannel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/myaudio"), att);
  notificationChannel.enableVibration(true);
  notificationChannel.setVibrationPattern(new long[]{ 400, 400});
  notificationChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
  NotificationManager manager = getSystemService(NotificationManager.class);
  manager.createNotificationChannel(notificationChannel);  
  }

Make sure you are adding the file without the extension. Note that the custom audio feature will not work on an android version less than 8. In devices less than android 8 you might need to play the audio from the application itself by listening to the events.

React native push notifications events

Once you receive the notifications we need to handle the application to interact with the notifications. Here you have various scenarios like,

  1. Forground state
  2. Background state
  3. Quit state

So we have to handle all of the above situations to make sure the application responds to the push notifications. React native firebase provides API methods that we can use to handle each situation.

Let’s start with the foreground state. Once you are in the application you can configure the event using the code which you can add inside your component’s effects.

//App.js
import messaging from '@react-native-firebase/messaging';

messaging().onMessage(async remoteMessage => {
  Alert.alert('A new puh notification arrived!', JSON.stringify(remoteMessage));
});

However, if the application is closed or in a background mode, you can use the following method in your application’s starting point such as the index.js file. The reason is being we do this we should not attempt to update the UI when a notification arrives in the background/quit state. However, you can update local storage or a local database.

//index.js
import messaging from '@react-native-firebase/messaging';

// Background notification handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
  console.log('Background/quit state message!', remoteMessage);
});

Also, if the application is closed we need to configure one more functionality of clicking the notification to open the application. Here we can add the following functions to open the app from either background/quit state.

To open the application from the background state:

//App.js

messaging().onNotificationOpenedApp(remoteMessage => {
  console.log(
    'Notification opened from background state:',
    remoteMessage.notification,
  );
});

To open the application from the quit state:

//App.js

messaging()
  .getInitialNotification()
  .then(remoteMessage => {
    if (remoteMessage) {
      console.log(
        'Notification opened from quit state:',
        remoteMessage.notification,
      );
    }
  });

Conclusion

To conclude, react-native push notifications can be a challenging task to achieve for most app developers as the libraries are difficult to configure and sometimes lacks certain features. However I hope this post has helped you to tackle the difficulties you are facing while implementing push notifications in react native. In addition to that, we also have other libraries like react-native push notifications and react-native notifications by Wix.

Hope you have a good read. Make sure you comment down below in case if you are still struggling  and we are open to any suggestions. Thank you!

3 thoughts on “React native push notifications using react native firebase”

Leave a Comment

Your email address will not be published.