Friday, 8 July 2016

Implement GCM Push Notification for Websites

If you ask a developer what feature is missing in web application, the first answer is PUSH NOTIFICATION. Notification is a great way to engage users to your website. So today i'm explaining push notification using Google Cloud Messaging for websites.


Project structure:

+-gcm-push-demo
|+-----images
|+--------icon192x192.png
|+-----index.html
|+-----manifest.json
|+-----myworker.js

Download Script                        Live Demo

Following are the steps we have to follow for implementing push messaging for 
chrome browser.

  1. Check if browser supports service worker & push messaging.
  2. Request user for push notification permission.
  3. Register a service worker with your browser.
  4. Get Server API key and Sender ID from GCM.
  5. Create manifest file.
  6. Subscribe for push messaging.
  7. Write some code for myworker.js
  8. Integrate all peace of code.
  9. Send push message to Website.
Check if browser supports service worker and push messaging.
//check if serviceWorker prsent in navigator
if(‘serviceWorker’ in navigator) {
    console.log('service worker is supported');
} else {
    console.warn('user denied the permission');
}
//check if push messaging supported or not
if('pushManager' in window) {
    console.log('push messaging is supported');
}
else {
    console.log('push messaging is not supported');
}
Request user for push notification permission.
Notification.requestPermission().then(function(permission) {
   if(permission === 'granted') {
     //here you can register your service worker
   } else {
     console.log('service worker not present');
   }
});
Register a service worker with your browser. 
Before registering a service worker with browser we will need service worker file which needs to be registered with service worker. Create a blank myworker.js file for now.
navigator.serviceWorker.register(‘/myworker.js’).then(function(registration){
    console.log(‘service worker registered with scope: ‘, registration.scope);
}).catch(function(err){
    console.error(‘service worker registration failed: ‘, err);
});
Get Server API key and Sender ID from GCM.
Generating server key and sender id is simple go to GCM websites and follow the instructions or you can follow my video tutorial.
Create a web manifest file.
The web app manifest provides information about an application in a simple document. We have to add gcm_sender_id in manifest file for subscribing to GCM server.
manifest.json
{  
  "name": "Web Push Demo",  
  "short_name": "GCM Push",  
  "icons": [{  
        "src": "images/icon-192x192.png",  
        "sizes": "192x192",
        "type": "image/png"
      }],  
  "start_url": "/index.html",  
  "display": "standalone",  
  "gcm_sender_id": "sender-id"
}
Subscribe to GCM for push messaging.
Finally we have to subscribe to GCM server using subscribe() method on the PushManager object through the serviceWorkerRegistration object.

navigator.serviceWorker.ready.then(function(serviceWorkerRegistration){
    serviceWorkerRegistration.pushManger.subscribe({userVisibleOnly:true})
    .then(function(subscription){
    console.log(‘subscription successful: ‘, subscription);
}).catch(function(err){
        console.error(‘unable to subscribe to GCM’, err);
});
});
Write some code for myworker.js 
myworker.js is the file which will be running in service worker thread of your web browser. Service worker is a javascript which is run by your browser in the background, write some code for receiving push message into your website.
myworker.js
self.addEventListener('push', function(event) {
  console.log('Push message received');
  var notificationTitle = 'New Message';
  const notificationOptions = {
    body: 'Push mesage received',
    icon: './images/icon-192x192.png',
    tag: 'simple-push-demo-notification',
    data: {
      url: 'http://ninjacoders.info'
    }
  };

  event.waitUntil(
    Promise.all([
      self.registration.showNotification(
        notificationTitle, notificationOptions)
    ])
  );
});
Above code will register an event listener for push messages and whenever push message comes from GCM this event get triggered.
self.addEventListener('notificationclick', function(event) {
  event.notification.close();

  var clickResponsePromise = Promise.resolve();
  if (event.notification.data && event.notification.data.url) {
    clickResponsePromise = clients.openWindow(event.notification.data.url);
  }

  event.waitUntil(
    Promise.all([
      clickResponsePromise
    ])
  );
});
Above code will register an event listener for notificationClick event and whenever user clicks on the notification window we will open a new web page.
Integrate all peace of code.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Push Notification for Web Application</title>
<link rel="manifest" href="/manifest.json">
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector("#enablepush")
                .addEventListener('click', function(e) {
if(Notification.permission !== 'granted') {
Notification.requestPermission().then(function(permission) {
if(permission === 'granted' && 'serviceWorker' in navigator) {
navigator.serviceWorker.register('myworker.js')
                                .then(initialiseState); 
} else {
console.log('service worker not present');
}
});
} 
});
//get subscription token if already subscribed
if(Notification.permission === 'granted') {
navigator.serviceWorker.ready.then(function(registration) {
registration.pushManager.getSubscription()
                            .then(function(subscription){
getToken(subscription);
});
});
}
});

function initialiseState() {

//check if notification is supported or not
if(!('showNotification' in ServiceWorkerRegistration.prototype)) {
console.warn('Notificaiton are not supported');
return;
}
//check if user has blocked push notification
if(Notification.permission === 'denied'){
console.warn('User has blocked the notification');
}
//check if push messaging is supported or not
if(!('PushManager' in window)) {
console.warn('Push messaging is not supported');
return;
}

//subscribe to GCM
navigator.serviceWorker.ready
                    .then(function(serviceWorkerRegistration) {
//call subscribe method on serviceWorkerRegistration object
serviceWorkerRegistration.pushManager
                            .subscribe({userVisibleOnly: true})
.then(function(subscription){
getToken(subscription);
}).catch(function(err){
console.error('Error occured while subscribe(): ', err);
});
});
}

function getToken(subscription) {
console.log(subscription);
var token = subscription.endpoint
        .substring(40, subscription.endpoint.length);
document.querySelector("#token").innerHTML = token; 
}
</script>
</head>
<body>
<h1>Push Notification for Web Application</h1>
<button id="enablepush">Enable Push</button><br />
<label for="token">Registration ID</label>
<textarea id="token" rows="6" cols="40"></textarea>
</body>
</html>
Send push message to Website.
Sending push notification we use GCM, we have to send post request to GCM along with authorization key (Server Key) and client token (i.e registration id)
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...fMwj0qwRt-bJvir
{   
    "data": 
    {
      "message": "How to create PayPal",
      "url": "http://www.ninjacoders.info/"
    },
   "to" : "fzeh02y7_p4:APA91bE-KxSmlLoJFyZftBlUkNsVXW..."
}
curl "https://android.googleapis.com/gcm/send" --request POST --header "Authorization: key=server_key" --header "Content-Type: application/json" -d "{\"to\":\"client_token\"}"
For sending push messages to your website you have to make POST request from your server copy paste above 'curl' and place your server_key and client_token. You can also use this tool and enter your server_key and client_token click on send notification button. Note: HTTPS is needed to register service worker on production but you can test it without HTTPS on your local server url should be http://localhost
You can use node http-server for deploy the app or you can use any server like wampp, xampp, lampp.
Final Words:
Integrate push notification in your website and engage more users.

27 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete

  3. Congratulations on tutorial,
    You could tell me how to do this same tutorial using the new API from google FCM.
    If the server side would be pointing to "https://fcm.googleapis.com/fcm/send" and not to "https://android.googleapis.com/gcm/send ".

    ReplyDelete
    Replies
    1. This comment has been removed by a blog administrator.

      Delete
  4. Sure i'll post the same tutorial using FCM, Soon google will deprecate GCM APIs.

    ReplyDelete
    Replies
    1. dear please solution this error ServiceWorker registration failed: DOMException: Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).

      Delete
    2. You can test this in your localhost, but when you want to deploy in production your app url must be HTTPS (SSL).


      thanks

      Delete
  5. Small question. In myworker.js how do I get the data that is transferred by cURL? Now you've just hardcoded the contents of the push message, but of course this should be dynamic.

    I'm struggling to find a way to get the data supplied by the cURL request?

    Thanks

    ReplyDelete
    Replies
    1. Message or data you want to send should be encrypted before sending. Check the link below and they even have library to encrypt the payload.

      https://developers.google.com/web/updates/2016/03/web-push-encryption?hl=en

      Delete
  6. Hi Akshay Kadu,

    So to clarify: Chrome browser for Android can be totally closed AND the service
    worker will remain running AND still respond to messages from the server AND
    show the notification message to the user.

    Thanks

    ReplyDelete
    Replies
    1. Exactly this is the beauty of service worker.

      thanks

      Delete
    2. Not exactly. Service Worker runs until browser is closed. You can close the website, but not Chrome. You receive your push messages when you start Chrome again.

      Delete
  7. This comment has been removed by a blog administrator.

    ReplyDelete
  8. Hi ,
    I have working on "FCM" for Android, Ios and Web Notification ,
    So i need your help for web notification using PHP.

    thank you.

    ReplyDelete
  9. Why are some of the comments deleted? The questions could provide us with a guide or some of us could even answer them?

    ReplyDelete
    Replies
    1. It's deleted because there were unnecessary backlinks.

      Delete
  10. This comment has been removed by a blog administrator.

    ReplyDelete
  11. Hi, using curl im getting invalid registration error, I have done everything correct. And in other approach used node-gcm for sending push notifications but still it doesnt show any notification

    ReplyDelete
  12. Hi Akshay,
    Please share your email id need to discuss something different with push notifications. My email id is [email protected]@gmail.com
    Thanks

    ReplyDelete
  13. This comment has been removed by the author.

    ReplyDelete
  14. Hi Akshay,
    can you list out the server side steps of encryption and sending message with new specifications (preferably in php code snippets)

    ReplyDelete
  15. Hi , you mentioned static data for notification, how can get dynamic data from server ?

    ReplyDelete
    Replies
    1. You can write your own REST API which will give the dynamic notification and call it using fetch() function.

      var notificationOptions = {};
      fetch(API_END_POINT).then(function(response) {
      notificationOptions = {
      body: response.body,
      icon: './images/icon-192x192.png',
      tag: response.tag,
      data: {
      url: response.url
      }
      };
      });

      Delete
  16. This comment has been removed by the author.

    ReplyDelete
  17. Hey how can I get the data I simply cant get the data might need some help

    ReplyDelete
  18. Hi can you help me i using web push notification configer but when i send push data by curl message not receive (data=""). i saw your last code but no i got any success. can explain how to send push data encrypted vie php curl program.

    ReplyDelete
  19. This comment has been removed by a blog administrator.

    ReplyDelete