Magic Mix of React Web App and Push Notification using FCM

Akshay Satheesh
6 min readApr 13, 2018

--

Following content was for educational purpose, and was true to the topic at the moment when it was originally posted, and is outdated as of now. Although the basic concepts of Service Workers, notifications, FCM remains the same the usage of methods provided by FCM has been changed.

We have all come across one or the other website which gives you a notification, which will popup out of nowhere, be there for sometime and then fades away. Something like this.

Do you want something like this for your site? Yes? Sure, but before we get our hands dirty, (well, it won’t be that dirty!), let’s go through some of the basics of what we are about to do and why. Push notifications are the use of the Notification API in conjunction with data sent over the Push API. They are one of the many features at the heart of giving Progressive Web Apps a truly competitive experience to their Native App counterparts. Much like Sockets, they allow a server to send data to the client without waiting for the client to initiate the transaction as is required over HTTP. Unlike Sockets, however, they allow the transfer of this data in the background while your app is closed. This is what allows a user to receive messages, event notifications, transaction updates, etc. even without having to have your app open.

Have you come across this kind of popup on your browser?

Why does this site want me to allow or block; what was it, notification or something?

This popup is asking the user of the site to allow or deny Notification permissions. So, this popup was the morality of the site to ask you permission to notify you on about something.

Service Worker, FCM and GCM

A service worker is a plain javascript file which acts as a middleman for you and the server, helping the process of loading faster, even when you’re offline. It’s a script that your browser runs in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. The scope of a SW includes folders from the current source folder to all the subfolders. So you better place your service worker in the root folder of the project so that SW is available in all parts and pages of your project. It is a programmable network proxy, allowing you to control how the network requests from your page are handled. Service workers make extensive use of promises. Explaining promises is out of our scope right now.

Google Cloud Messaging was one of the ways where you could send push notifications to your clients on phone or on web, which got deprecated on April 10th, 2018. So we have to use Firebase Cloud Messaging, which is relatively very easy.

How Do I Use FCM on my React Application?

First thing you want to do is, go to your firebase console, https://console.firebase.google.com, and create a project to integrate FCM to. From the project settings on console, you can add Firebase App to your web application.

You will get something like this when trying to add.

var config = {
apiKey: "AIzaSyAfeR2E4NycgG_xYEfVL1DIYRw….._qL8XKlA",
authDomain: "appName.firebaseapp.com",
databaseURL: "https://appName.firebaseio.com",
projectId: "appName",
storageBucket: "appName.appspot.com",
messagingSenderId: "210106….862"
};

In the above code snippet, what you actually need is just the “ messagingSenderId: "21010….862" ”. So you can just remove the rest and save the config variable in a file called “firebaseConfig.js”

Now that you have firebaseConfig all set up, it’s time to use that in your application. Install firebase plugin to your react app using npm or yarn. (npm install — save firebase)

Now let’s integrate it.

In your main JS file (index.js/main.js), import the firebase plugin and the config file you created and initialize your app with firebase using the configuration.

import { config } from "./push/firebaseConfig";
import firebase from "firebase";
firebase.initializeApp(config);

Now, let’s deal with the part where we ask the permission of the user to allow or deny push notifications. We also need to generate FCM token unique to the current instance of the user session, be it on a phone or a tab on desktop browser.

import firebase from "firebase";
export function initializePush() {
const messaging = firebase.messaging();
messaging
.requestPermission()
.then(() => {
console.log("Have Permission");
return messaging.getToken();
})
.then(token => {
console.log("FCM Token:", token);
//you probably want to send your new found FCM token to the
//application server so that they can send any push
//notification to you.
})
.catch(error => {
if (error.code === "messaging/permission-blocked") {
console.log("Please Unblock Notification Request
Manually");
} else {
console.log("Error Occurred", error);
}
});
}

Save the above code as “initialize.js”. Call this function when loading the application and it will ask you to allow or block push notification when you run the application.

Now that you have handled “Asking for permission” section, let’s deal with push notification reception.

Go on and create a service worker named “firebase-messaging-sw.js” and place it in the root folder. (I have told you why.)

importScripts("https://www.gstatic.com/firebasejs/4.12.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/4.12.0/firebase-messaging.js");
let config = {
messagingSenderId: "210106….862"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(payload => {
const title = payload.notification.title;
console.log('payload', payload.notification.icon);
const options = {
body: payload.notification.body,
icon: payload.notification.icon
}
return self.registration.showNotification(title, options);
})

Well, that would handle the “show notification” part of push notification. Wouldn’t you want to handle what happens when you click on it?

Add this to your service worker.

self.addEventListener("notificationclick", function(event) {
const clickedNotification = event.notification;
clickedNotification.close();
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
let matchingClient = null;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.url === feClickAction) {
matchingClient = windowClient;
break;
}
}
if (matchingClient) {
return matchingClient.focus();
} else {
return clients.openWindow(feClickAction);
}
});
event.waitUntil(promiseChain);
});

Now, you might probably be thinking, “Where and how do I subscribe this service worker file onto my application if I am using a webpack module bundler?” Worry not, I have a solution for you. Nah.. npm has a solution for you. Use “npm install — save-dev serviceworker-webpack-plugin” and you have got yourself a new webpack plugin.

Go to your webpack configuration file and add this piece of code.

const ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin');   plugins: [
….
new ServiceWorkerWebpackPlugin({
entry: path.join(__dirname, './firebase-messaging-sw.js'),
})
]

Now that you have handled push notification while away from the application, you may now want to handle the same on the page too. FCM provides this method for handling push while on the page. Add this method in your initialize.js file:

import firebase from "firebase";export function initializePush() {
const messaging = firebase.messaging();
….
else {
console.log("Error Occurred", error);
}
});
messaging.onMessage(payload => {
console.log("Notification Received", payload);
//this is the function that gets triggered when you receive a
//push notification while you’re on the page. So you can
//create a corresponding UI for you to have the push
//notification handled.
});
}

That’s all folks!

Time to test our push notification. Use the curl command:

curl -X POST --header "Authorization: key=<AppServerKey>" --header "Content-Type: application/json" -d "{\"to\":\"<FCMToken_Generated>\",\"priority\":\"high\",\"notification\":{\"body\": \"FOO BAR BLA BLA\"}}" "https://fcm.googleapis.com/fcm/send"

Ta-da!

Oh, FYI.. AppServerKey can be found on the same settings page of your firebase console.

For the production build, you have to copy the service worker to your build folder, so that the service worker will be registered. For that, use the copy-webpack-plugin from npm, “npm install — save-dev copy-webpack-plugin” and do this in your webpack configuration.

const CopyWebpackPlugin = require('copy-webpack-plugin');   plugins: [
….
new ServiceWorkerWebpackPlugin({
entry: path.join(__dirname, './firebase-messaging-sw.js'),
}),
new CopyWebpackPlugin([
'firebase-messaging-sw.js',
])
]

--

--