DEV Community

Gabriel Dantas
Gabriel Dantas

Posted on • Updated on

Push Notifications using Firebase in PWAs built with Expo

So you built your PWA using Expo and now you need to integrate it with firebase Cloud Messaging to receive push notifications? In this tutorial I am going to show a way to do this integration.
At the end I will link a repository with all codes shown here

Let's start it!

The first step is add firebase to your expo project

npm install firebase@latest

(It is important to install latest version, expo dependencies ask for Firebase version 7.9.0 but the solution presented here requires a newer Firebase version)

After installing firebase, we need to create a service worker for it.

expo customize:web

And select:

web/register-service-worker.js

A new folder called web will be created on your project root folder, inside it you will find register-service-worker.js file.

Imagem1

Inside this folder you must create a file called firebase-messaging-sw.js, you can leave it blank now
Now open the register-service-worker.js and add a new line to it:

.register('SW_PUBLIC_URL/firebase-messaging-sw.js', { scope: 'SW_PUBLIC_SCOPE' })
Enter fullscreen mode Exit fullscreen mode

As you can see below:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function () {
    navigator.serviceWorker
      .register('SW_PUBLIC_URL/expo-service-worker.js', { scope: 'SW_PUBLIC_SCOPE' })
      .register('SW_PUBLIC_URL/firebase-messaging-sw.js', { scope: 'SW_PUBLIC_SCOPE' })
      .then(function (info) {
        // console.info('Registered service-worker', info);
      })
      .catch(function (error) {
        console.info('Failed to register service-worker', error);
      });
  });
}
Enter fullscreen mode Exit fullscreen mode

Now let’s go to firebase console and set our Cloud Messaging credentials.
Select Cloud Messaging on your console and then add an web app to it:

Imagem3

Register yor app,

Imagem4

You can also set up Firebase Hosting, if you do not have a hosting server yet, it can be a great option as FCM push notifications work only on https domains and firebase hosting provides you a https address.

No go to your project settings

Imagem5

And under “Your Apps” section you can find your app credentials

n4e0wonexddlhm4gxd0n (1)

Copy these credentials and now you need to initialize your app.
Now back to the firebase-messaging-sw.js you are going to use it to make your App be able to receive notifications while it is running on background! This step is the same as configuring a regular PWA that was not created with expo.
Your firebase service worker must be coded like this:

importScripts('https://www.gstatic.com/firebasejs/7.22.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.22.1/firebase-messaging.js');
importScripts("https://www.gstatic.com/firebasejs/7.22.1/firebase-analytics.js");

firebase.initializeApp({
    apiKey: "xxxxxxxxxxxxxxxxxxxx",
    authDomain: "project.firebaseapp.com",
    databaseURL: "https://project.firebaseio.com",
    projectId: "projectId",
    storageBucket: "project.appspot.com",
    messagingSenderId: "00000000000000",
    appId: "xxxxxxxxxxxxxxxxxxxxx",
    measurementId: "G-XXXXXXX"
});

const messaging = firebase.messaging();
Enter fullscreen mode Exit fullscreen mode

There is an extra step to retrieve your FCM push token and make your app able to receive messages in foreground. In the following solution there is no need to deal with index.html generated by expo, which can be a bit messy.
For this I like to create a separate folder called firebase in project root folder and inside that a config.js file.
The config file is created as you can see below:

import firebase from "firebase/app"
import "@firebase/messaging";

const firebaseConfig = {
    apiKey: "xxxxxxxxxxxxxxxxxxxx",
    authDomain: "project.firebaseapp.com",
    databaseURL: "https://project.firebaseio.com",
    projectId: "projectId",
    storageBucket: "project.appspot.com",
    messagingSenderId: "00000000000000",
    appId: "xxxxxxxxxxxxxxxxxxxxx",
    measurementId: "G-XXXXXXX"
};

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}

export { firebase };
Enter fullscreen mode Exit fullscreen mode

Back to App.js file you should now initialize firebase in your PWA so it will be able to receive foreground push notifications.

I do this by importing firebase from config.js by calling:

import { firebase as firebaseInit } from “./firebase/config”

Then you should import firebase messaging again and retrieve a FCM push token

import { fireabase as firebaseInit } from "./firebase/config";

import firebase from "firebase/app";
import "firebase/messaging";

let pushToken;
const messaging = firebase.messaging();
messaging
  .getToken()
  .then((currentToken) => {
    if (currentToken) {
      console.log("FCM token> ", currentToken);
      pushToken = currentToken;
    } else {
      console.log("No Token available");
    }
  })
  .catch((error) => {
    console.log("An error ocurred while retrieving token. ", error);
  });
Enter fullscreen mode Exit fullscreen mode

Now you have your token, let’s add the capability to receive the notifications in foreground:

messaging.onMessage((payload) => {
  console.log("Message received. ", payload);
  const { title, ...options } = payload.notification;
  navigator.serviceWorker.register("firebase-messaging-sw.js");
  function showNotification() {
    Notification.requestPermission(function (result) {
      if (result === "granted") {
        navigator.serviceWorker.ready.then(function (registration) {
          registration.showNotification(payload.notification.title, {
            body: payload.notification.body,
            tag: payload.notification.tag,
          });
        });
      }
    });
  }
  showNotification();
});
Enter fullscreen mode Exit fullscreen mode

Please note that this solution will ask for permission every time a new message arrives, and this is considered a violation since this behavior should occur in response to a user gesture. As this is a simple tutorial I have not implemented a solution to check for those permissions in advance.

And It is done!

Let's test it.

Just run your project in web:

expo start:web

And now your browser should ask for permissions to show notifications

Imagem9

And at your browser's console you can find your FCM push token

Imagem10

Let’s send some test messages!
Back to your firebase console, go to FCM and select “send your first message”
You will land in the following page:

Imagem11

Put in a notification title and a notification text and click on send test message

Imagem12

Paste your FCM push token and click in test.

Wait a few seconds and you will have your notification right there!

With the app in background:

Imagem13

And in foreground:

Imagem14

Now you can tweak your application and notifications as you like!

I hope this tutorial was useful for you! You can find this sample app at: https://github.com/GabrielNSD/expo-fcm-pwa

If you have any suggestion or different way to do this integration let me know!

You can learn more about Firebase Cloud Messaging here: https://firebase.google.com/docs/cloud-messaging

For better understanding Notifications API you can take a look here:

https://developer.mozilla.org/en-US/docs/Web/API/notification

Top comments (1)

Collapse
 
mcontagious profile image
Kishore Relangi

expo customize:web

is not providing service worker option.