coinpayu

    Push Notifications enable you to bring information to the attention of your users even when they're not using your website. They're called Push Notifications because you can "push" information to your users even when they're not active.

Prerequisite

  • Firebase Account
  • Wamp/Xampp Server for testing in local (If you have any https hosted site, you can also test directly in your site. No need any local servers)
  • Visual Studio Code / Any other IDE
  • Chrome or any other browsers

Notes:  Without HTTPS Hosting or local servers even in Incognito mode Firebase can't send messages to their registered clients. Because firebase only can send messages to trusted parties. Otherwise It shows the following error. 


FirebaseError: Messaging: The notification permission was not granted and blocked instead.

 

Firebase Cloud Messaging ( FCM )

Firebase Cloud Messaging (FCM) provides a reliable and battery-efficient connection between your server and devices that allows you to deliver and receive messages and notifications on iOS, Android, and the web at no cost.

How does it work?

An FCM implementation includes two main components for sending and receiving:
  • A trusted environment such as Cloud Functions for Firebase or an app server on which to build, target, and send messages.
  • An iOS, Android, or web (JavaScript) client app that receives messages via the corresponding platform-specific transport service.

Before we start you need the FCM server key, sender id & etc. For that, you need to create a project at https://console.firebase.google.com/

Following steps will guide you how to integrate FCM in your web app. Complete sample code can be obtained from here.

Create Firebase Project:

  1. In the Firebase console, click Add project, then select or enter a Project name. For example see the below images






  1.  When your project  is created. Then click on continue. Then you will see something like the picture below.



 

Register your app with Firebase:

After you have a Firebase project, you can add your web app to it.

  1. In the center of the Firebase console's project overview page, click the Web icon (</>) to launch the setup workflow.

  2. Enter your app's nickname. Then Continue




  1. Now we have a set of configurations for our web app. Later we use this to access Firebase services. Click Continue to console for Register app.




Add Firebase SDKs and initialize Firebase:

  1. Create an index.html file, Then Add Firebase scripts in your index.html/web app like below.

     

<script defer src="https://www.gstatic.com/firebasejs/8.2.8/firebase-app.js"></script>


<script defer src="https://www.gstatic.com/firebasejs/8.2.8/firebase-messaging.js"></script>


<script defer src="./init-firebase.js"></script>

  1. Create an init-firebase.js file in your project folder, then include the following Firebase initialization in the file: 

Notes: Replace the following with your app's Firebase project configuration before we created it.
 
// your app's Firebase config object.
var firebaseConfig = {
    apiKey: 'api-key',
    authDomain: 'project-id.firebaseapp.com',
    databaseURL: 'https://project-id.firebaseio.com',
    projectId: 'project-id',
    storageBucket: 'project-id.appspot.com',
    messagingSenderId: 'sender-id',
    appId: 'app-id',
    measurementId: 'G-measurement-id',
  };

  // Initialize Firebase  
  firebase.initializeApp(firebaseConfig);

 

Configure Web Credentials with FCM:

The FCM Web interface uses Web credentials called "Voluntary Application Server Identification" or "VAPID" keys, to authorize send requests to supported web push services. To subscribe your app to push notifications, you need to associate a pair of keys with your Firebase project. You can generate a new key pair through the Firebase Console.



So there are two reasons for VAPID:
  • The first is to restrict the validity of a subscription to a specific application server (so, by using VAPID, only your server will be able to send notifications to a subscriber).
  • The second is to add more information to the push notification, so that the push service operator knows who is sending the notifications. If something is going wrong with your notifications, the operator knows who you are and can contact you. Moreover, they can offer you some kind of interface to monitor your push notifications.


Generate a new key pair

  1. Open the Cloud Messaging tab of the Firebase console Settings pane and scroll to the Web configuration section.

  2. In the Web Push certificates tab, click Generate Key Pair. The console displays a notice that the key pair was generated, and displays the public key string and date added.





Creating Service Worker JS:

Firebase messaging service requires a firebase-messaging-sw.js file at the root of the web folder. Without this file, you will get some errors like below. 


An error occurred while retrieving token.  FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost/firebase-cloud-messaging-push-scope') with script ('http://localhost/firebase-messaging-sw.js'): A bad HTTP response code (404) was received when fetching the script. (messaging/failed-service-worker-registration).


Sample service worker file given below, (firebase-messaging-sw.js)

 

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

firebase.initializeApp({
    apiKey: 'api-key',
    authDomain: 'project-id.firebaseapp.com',
    databaseURL: 'https://project-id.firebaseio.com',
    projectId: 'project-id',
    storageBucket: 'project-id.appspot.com',
    messagingSenderId: 'sender-id',
    appId: 'app-id',
    measurementId: 'G-measurement-id',
});

const messaging = firebase.messaging();

messaging.onBackgroundMessage(function (payload) {
    // Customize notification here
    const msgPayload = JSON.parse(payload);
    const notificationTitle = msgPayload.notification.title;
    const notificationOptions = {
        body: msgPayload.notification.body,
        icon: msgPayload.notification.icon,
        image: msgPayload.notification.image,
        click_action: msgPayload.notification.click_action,
        data: {
            time: new Date(Date.now()).toString(),
            body: msgPayload.data.body,
            title: msgPayload.data.title,
            siteName: msgPayload.data.siteName,
            notification_type: msgPayload.data.notification_type,
            itemId: msgPayload.data.itemId,
            click_action: msgPayload.data.click_action
        }
    };

    self.registration.showNotification(notificationTitle,
        notificationOptions);
});

self.addEventListener("notificationclick", (event=> {
    event.waitUntil(async function () {
        const allClients = await clients.matchAll({
            includeUncontrolled: true
        });
        let chatClient;
        let appUrl = 'URL';
        for (const client of allClients) {
            //here appUrl is the application url, we are checking it application tab is open
            if (client['url'].indexOf(appUrl) >= 0) {
                client.focus();
                chatClient = client;
                break;
            }
        }
        if (!chatClient) {
            chatClient = await clients.openWindow(appUrl);
        }
    }());
});
 

This service worker file used to get the registrations token and also used to receive the messages from background even browsers are in closed state.

 

Alternatively, you can add your custom service worker file path for generating registration tokens like the method to use is useServiceWorker(<registration>).

see below, 

 

 
// register service worker
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('./fcm-service-worker.js')
        .then((registration=> {
            firebase.messaging().useServiceWorker(registration);
            console.log("Service Worker Registered");
            init();
        }).catch((error=> {
            console.log('Registration failed with ' + error);
        });
    }
 

 

Note: You should do this as early as possible, before any calls to e.g. getToken() or onMessage().

Receive Messages:

The behavior of messages differs depending on whether the page is in the foreground (has focus), or in the background, hidden behind other tabs, or completely closed. In all cases the page must handle the onMessage callback, but in background cases you may also need to handle onBackgroundMessage or configure the display notification to allow the user to bring your web app into the foreground.


Sample code: (init-firebase.js)


 
function init() {
    try {
        if (firebase.messaging.isSupported()) {
            const messaging = firebase.messaging();

            messaging
                .requestPermission()
                .then(function () {
                    console.log("Notification permission granted.");
                    // get the token in the form of promise
                    return messaging.getToken();
                }).then((currentToken=> {
                    if (currentToken) {
                        console.log('Token'currentToken);
                        subscribeTokenToTopic(currentToken'news');
                    } else {
                        console.log('No registration token available. Request permission to generate one.');
                    }
                }).catch((err=> {
                    console.log('Notification permission/Token error:'err);
                });

            // receiving messages from FCM
            messaging.onMessage((payload=> {
                console.log(payload);
                appendMessage(payload);
            });

            // appending push messages
            function appendMessage(payload) {
                if (!("Notification" in window)) {
                    alert("This browser does not support desktop notification");
                } else if (Notification.permission === "granted") {
                    createNotification(payload.notification);
                } else {
                    Notification.requestPermission(permission => {
                        if (permission === 'granted') {
                            createNotification(payload.notification);
                        }
                    });
                }
            }
        } else {
            console.log('firebase messaging not supported');
        }
    } catch (err) {
        console.log(err);
    }
}

    // Notification creator
    function createNotification({
        title,
        body,
        icon,
        image,
        tag,
        badge,
        click_action
    }) {
        var notification = new Notification(title, {
            body: body,
            icon: icon,
            vibrate: [10050100],
            tag: tag,
            image: image,
            badge: badge,
        });
        notification.onclick = function (event) {
            event.preventDefault(); // prevent the browser from focusing the Notification's tab
            window.open(click_action'_blank');
            notification.close();
        }
    }
 

 

We need to get a registration token by using  messaging.getToken() then we can send messages to this registered client. And you can get the message payload using messaging.onMessage() then show push message using Notification API.


Send Messages

You can send messages in two different ways. By using the default Notifications composer of the FCM. There is no need for any code to sending test messages. Sample image below. (Need to add registration token generated in your client device before send test message)





Another way to send messages is using the FCM send API.


Example: 

 


fetch('https://fcm.googleapis.com/fcm/send', {
    method: 'post',
    headers: new Headers({
        'Authorization': 'key=server key',
        'Content-Type': 'application/json'
    }),
    body: JSON.stringify({
        "to": "registration token from firebase getToken()",
        "notification": {
            "title": "title",
            "body": "body",
            "icon": "icons",
            "image": "image",
            "click_action": "NOTIFICATION_CLICK_ACTION_URL"
        },
        "data": {
            "body": "body",
            "title": "title",
            "siteName": "sites/sitename",
            "notification_type": "type",
            "listName": "list",
            "itemId": "Id",
            "click_action": "NOTIFICATION_CLICK_ACTION_URL"
        }
    })
}).then(function (response) {
    return response.json();
}).then(function (data) {
    console.log('Now you can receive new message!');
});


 


Send Messages to Multiple devices

Firebase Cloud Messaging provides these two ways to target a message to multiple devices:


  • Topic messaging, which allows you to send a message to multiple devices that have opted in to a particular topic.
  • Device group messaging, which allows you to send a message to multiple devices that belong to a group you define.

Topic messaging:


Before sending topic based messages, You need to subscribe users to specific topic. Then you can send messages to all the users who will subscribed in relevant topic, at same time.

 

You can subscribe users in two ways. Using Firebase admin SDK as mentioned in FCM official documentation. But in this method you need node.js for accessing admin SDK. Another way is using Firebase subscription API, see in below example


Example: For subscribe users,

 

 
function subscribeTokenToTopic(tokentopic) {
    fetch(`https://iid.googleapis.com/iid/v1/${token}/rel/topics/${topic}`, {
        method: 'POST',
        headers: new Headers({
            'Authorization': 'firebase server-key',
        }),
    })
        .then((response=> {
            if (response.status < 200 || response.status >= 400) {
                console.log(response.statusresponse);
            }
            console.log(`"${topic}" is subscribed`);
        })
        .catch((error=> {
            console.error(error.result);
        });
    return true;
}
 

After subscribe, You can send notification to all your subscribed users by only using topic name with Firebase send API like below,


 
bodyJSON.stringify({
    "to": "/topics/news",
    "notification": {
        "title": title,
        "body": body,
        "icon": icons,
    } ...
})
 


Device group messaging:


This is similar to topic messaging, but includes authentication to ensure that group membership is managed only by your servers. 


For example, Just send a parameters with a group of Tokens in send request body like,

 

 
bodyJSON.stringify({
    "operation": "create",
    "notification_key_name": "appUser-Chris",
    "registration_ids": ["4""8""15""16""23"],
    "notification": {
            "title": title,
            "body": body
    } ...
})
 


    Thanks for reading this post, Please share your thoughts about how helpful is this to you or if any mistakes and do support to add more post. Also add comments if you have any doubts in this.