Web Push Notification with Service Worker


Posted on Apr 15th, 2016


The web is getting better and better. Its getting closer and closer to native mobile apps. This writeup is about the magic the of service workers. Few of its features are:

  • Push Notifications
  • Caching
  • Offline requests
  • Creating response without hitting the server

This article is going to cover Push Notifications. Push notifications is great when it comes to re-engaging your visiters or sending updates about a new feature or blog or anything.

Prerequisites:

  1. You will need https protocol for using service worker.
  2. Google API Key and Sender ID

To get the Google API Key and Sender, please visit this link. It has step by step images on how to get these.

Lets get started. First we will create the service worker. This is a javascript file. We will register this file in the browser later. The service workers is always listening to events even if your site is not open on any tab.

serviceWorker.js

//We are going to store the url which will open when we click the notification.
var urlAction;

//Send notification to client
self.addEventListener("push", function(event) {

    event.waitUntil(

        fetch("http://localhost/api/getNotification", {
            method: "get",
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json"
            }
        }).then(function(response) {
            return response.json()
        }).then(function(result) {
            //set the url action
            urlAction = result.msg.data.action;
            self.registration.showNotification(result.msg.data.title, {
                body: result.msg.data.msg,
                icon: result.msg.data.logo,
                tag: result.msg.data.name
            });

        })
    )
});

The above snippet is listening for a push event. The moment it receives it, we send a request to the server to get the content of the notification and then show the notification popup.

Cool, now when users receives a notification, then would likely click on the notification. At that point, we will open a particular link which corresponds to the notification. So lets add another event handler.

self.addEventListener("notificationclick", function(event) {
    
    // close the notification
    event.notification.close();

    //To open the app after click notification
    event.waitUntil(
        clients.matchAll({
            type: "window"
        })
        .then(function(clientList) {
            for (var i = 0; i < clientList.length; i++) {
                var client = clientList[i];
                if ("focus" in client) {
                    return client.focus();
                }
            }

            if (clientList.length === 0) {
                if (clients.openWindow) {
                    return clients.openWindow(urlAction);
                }
            }
        })
    );
});

The for-loop in the above snippet, checks if any tab is already open. If yes, then will focus that tab. If not, then we open a new tab/window with the appropriate url.

Registering the Service Worker:

script.js

navigator.serviceWorker
         .register(server + "/serviceWorker.js") //Point to serviceWorker file
         .then(function(registration) {
              // Registration was successful
              console.log('Registration successful with scope: ',registration.scope);
          })
          .catch(function(error) {
              console.error("Failed to register service worker", error);
          });

Include this script in your index.html file.

Permission to receive Push Notification

We need to take permission from the user to send push notifications. This permission will give us a registration_id which we will use to send notifications from Google Cloud Messaging.

navigator.serviceWorker.ready
    .then(function(registration) {
        if (!registration.pushManager) {
            //alert("Your browser doesn't support push notifications");
            return;
        }

        registration.pushManager.subscribe({
                userVisibleOnly: true //To always show notification when received
            })
            .then(function(subscription) {
                var temp = subscription.endpoint.split("/");
                var registration_id = temp[temp.length - 1];
                //store this in your db
                console.log(registration_id);
            })
            .catch(function(error) {
                //push is in denied state, maybe!
                console.error(error);
            })
    })

In the above snippet, you should store the registration_id in your database.

Create a manifest file

At its most basic, “installation” of a web app means “bookmarking” the web application to the homescreen or adding it to an application launcher. There are some pretty obvious things that you, as a developer, would need to provide to the browser so that it can treat your website as an app: the name, icons, etc. There are then more advanced features that you would need, like being able to indicate the preferred orientation and if you want your app to be fullscreen.

The Manifest file aims to give you a standardised way to do this using JSON. In the HTML page to be “installed”, simply link to a manifest file, thus:

{
  "name": "Web Push Demo",
  "short_name": "push_demo",
  "version": "1.0.0",
  "description": "A simple site with push notification",
  "author": {
    "name": "Abhishek Saha"
  },
  "gcm_sender_id": "YOUR-GCM-ID GOES HERE",
  "gcm_user_visible_only": true
}

Although this is not the complete manifest file, but this is enough to get our push notifications work. The gcm_sender_id is most important part.

You can link this manifest file in your index.html just with this line:

<link rel="manifest" href="/manifest.json">

Sending the Push Notification

$fields = array
(
	'registration_ids' 	=> array($registrationId)
);
 
$headers = array
(
	'Authorization: key=' . API_KEY,
	'Content-Type: application/json'
);
 
$ch = curl_init();
curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send' );
curl_setopt( $ch,CURLOPT_POST, true );
curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );
$result = curl_exec($ch );
curl_close( $ch );
echo $result;

The above php script uses curl to send a request to the google push url along with the registration id's. You can send multiple registration id's with this request.


Google API Key and Sender ID for Web Push NotificationsChrome extension fix - This extension may have been corrupted

Comments


  • Apr 19, 2016, 12:17 PMTim Craig
    Fantastic writeup. Worked in one shot. Didn't find a subscribe box. Is there any way I can be notified of your posts?
  • Apr 21, 2016, 1:24 AMAlessandro
    Hi! What is this path "http://localhost/api/getNotification"?
  • Apr 21, 2016, 1:38 AMAjaxtown
    @Alessandro - Thats the server url from where you are going to fetch the notification. You should change that url to match your server name.
  • May 2, 2016, 3:30 AMelena
    Could you put online an archive file containing all the sources of the demo.... It would help me a lot....Thanks in advance.
  • Dec 4, 2016, 1:51 AMJesus Reyna
    What is $registrationId or how can I get that value? Thanks
  • Jan 5, 2017, 8:38 AMsanjay radadiya
    hi i have also confusion about http://localhost/api/getNotification so can you post code for this methods ?
100% Complete