Push Notifications using Firebase in PWAs built with Expo
Tags: reactnative, javascript, pwa, tutorial
Published: 2020-10-11 03:23:46

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](https://dev-to-uploads.s3.amazonaws.com/i/m5r21lmmkmm47j1ec7ol.png)
 
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: 

```javascript
.register('SW_PUBLIC_URL/firebase-messaging-sw.js', { scope: 'SW_PUBLIC_SCOPE' })
```

As you can see below: 

```javascript
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);
      });
  });
}
```

 
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](https://dev-to-uploads.s3.amazonaws.com/i/i45k6tc2ir8pvyz8fao2.png)

Register yor app,

![Imagem4](https://dev-to-uploads.s3.amazonaws.com/i/pwynxwl32mbg1prc2umy.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/calvbsleh8cva08p0v8z.png)

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

![n4e0wonexddlhm4gxd0n (1)](https://dev-to-uploads.s3.amazonaws.com/i/zlmdjt7cr7b8z9fhzh5o.png)
 

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:

```javascript
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();
```


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:

```javascript
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 };
```

 

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

```javascript
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);
  });
```


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

```javascript
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();
});
```

 
*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](https://dev-to-uploads.s3.amazonaws.com/i/s8c2a6ecgmb19a8adoqu.png)
 
And at your browser's console you can find your FCM push token

![Imagem10](https://dev-to-uploads.s3.amazonaws.com/i/iibiepwxwbn45kgs0ih1.png)
 

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](https://dev-to-uploads.s3.amazonaws.com/i/r4obzxyh8q2yn0k02z77.png)
 
Put in a notification title and a notification text and click on send test message

![Imagem12](https://dev-to-uploads.s3.amazonaws.com/i/kjqinkklxyxt9l7o0i95.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/iovdyn1f32bzra0veec7.png)

And in foreground:

![Imagem14](https://dev-to-uploads.s3.amazonaws.com/i/m0uocpi66t4sztxnniwo.png)

 
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