© Carlos Rojas 2020
C. RojasBuilding Progressive Web Applications with Vue.js https://doi.org/10.1007/978-1-4842-5334-2_8

8. Push Notifications

Carlos Rojas1 
(1)
Medellin, Colombia
 
One of the reasons why I think that service workers are starting to be used in web apps is to add the push notifications capability (Figure 8-1).
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig1_HTML.jpg
Figure 8-1

Allowing push notifications in web and mobile devices

Having push notifications allows us to interact with our users even when they have closed our app. This is common in the mobile world, but inside the web world, it was something that could not be achieved easily until now.

What Is a Push Notification?

Think, for a moment, about your chat app on your mobile phone. When you use the app, you can see messages and notifications when people write to you. However, what happens when you aren’t using the app? Although the app is closed, the notification is “pushed” to you without you needing to do anything, and you see it in the notification center.

Technically speaking, a push notification is basically an interaction that includes a push API and a notification API.

Here is the sequence:
  1. 1.

    Your app requires permission from the user to send notifications.

     
  2. 2.

    Your app contacts the push service to create a new subscription for the user.

     
  3. 3.

    The messenger service returns an object with relevant information.

     
  4. 4.

    Your app sends that information to the server to be stored for future use.

     
  5. 5.

    The server sends messages to the user with the stored information.

     
  6. 6.

    The service worker listens to the messages.

     
  7. 7.

    The service worker notifies the user of the message.

     

Push API

The push API gives your app the capacity to receive push messages sent from a server. As mentioned previously, for an app to receive push messages, it must have an active service worker. Thanks to the active service worker, we can use PushManager.subscribe() to allow users to subscribe to our service notifications.

A general use example is as follows:
navigator.serviceWorker.register(sw.js').then(
 (serviceWorkerRegistration) => {
    var options = {
      userVisibleOnly: true,
      applicationServerKey: applicationServerKey
    };
    serviceWorkerRegistration.pushManager.subscribe(options).then(
      function(pushSubscription) => {
        console.log(pushSubscription.endpoint);
      }
    );
  });

When using applicationServerKey (a token we get from our back end or a service such as Firebase Cloud Messaging), we allow user subscription. If you want to know more details about the push API, go to https://www.w3.org/TR/push-api/.

Notifications API

The notifications API allows an app to show a system notification even if the app is closed by the user (Figure 8-2).
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig2_HTML.jpg
Figure 8-2

Notifications API

Asking for Permission

If our app has the capacity to send push notifications, the first thing we must do is ask permission from the user to send them. To handle this scenario, we create the following function:
function showMe() {
  if (!("Notification" in window)) {
    console.log("Does not support notifications");
  }
  else if (Notification.permission === "granted") {
      new Notification("Hello World!");
  }
  else if (Notification.permission !== 'denied') {
    Notification.requestPermission(function (permission) {
          if (permission === "granted") {
         new Notification("Hello World!");
      }
    });
  }
}

With this function, we are ready to handle the permission action from our users.

Creating a Notification

We can create a function using the Notification() builder, which allows us to generate notifications easily in the following way:
function createNotification(theBody,theIcon,theTitle) {
  var options = {
      body: theBody,
      icon: theIcon
  }
  var n = new Notification(theTitle,options);
  setTimeout(n.close.bind(n), 5000);
}

This function sends parameters to the builder and it generates a new notification. If you want to know all the properties, go to https://developer.mozilla.org/en-US/docs/Web/API/notification.

Using Push Notifications in VueNoteApp

Now that we’ve taken a look at the principle APIs and the process for pushing notifications, let’s add this feature to our app.

Configuring the App

In our Firebase project, select Project settings (Figure 8-3).
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig3_HTML.jpg
Figure 8-3

Firebase project settings

In Project settings, select Cloud Messaging (Figure 8-4). Note the server key and the sender ID for later use.
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig4_HTML.jpg
Figure 8-4

Firebase Cloud Messaging

Next we need to add gcm_sender_id, which is “103953800507” to all the apps in the world that use the Firebase service. We add this property to our manifest.json file:
"gcm_sender_id": "103953800507"

Okay. Now we are ready to use cloud messaging in VueNoteApp.

Adding a Push Notification

Let’s add some values to firebase.js :
import firebase from 'firebase/app';
import 'firebase/database';
import 'firebase/messaging';
First, we import firebase/messaging to our app, then we add some code in Dashboard.vue . Next we need to add a constant
const messaging = fireApp.messaging();
and some extra data
  data: () => ({
    pages:[],
    newTitle: ",
    newContent: ",
    index: 0,
    dialog: false,
    showAlert: false,
    alertContent: 'demo'
  }),

We need showAlert and alertContent properties to handle when a notification is sent to our PWA.

Then we use retrieveMessaging() in Dashboard.vue to get the permission and the token to identify our device.
    retrieveMessaging () {
      // Retrieve Firebase Messaging object.
      messaging.requestPermission()
      .then(() => {
        //Notification permission granted.
      messaging.getToken()
      .then((currentToken) => {
        if (currentToken) {
          console.log("token:" + currentToken );
        } else {
          // Show permission request.
          console.log('No Instance ID token available. Request permission to generate one.');
        }
      })
      .catch((err) => {
        console.log('An error occurred while retrieving token. ', err);
      });
      this.onMessage();
      })
      .catch(function(err) {
        console.log('Unable to get permission to notify.', err);
      });
    }
We use the token later. We also need to use the onMessage() method to show our notification:
    onMessage() {
      messaging.onMessage((payload) => {
          console.log("Message received. ", payload);
          this.showAlert = true;
          this.alertContent = payload.notification.body;
        });
    }
Here we show the notification and the text in our app. We also need to use the v-alert component in the template. You can find more information at https://vuetifyjs.com/es-MX/components/alerts.
 <v-alert
        v-model="showAlert"
        type="info"
        dismissible
      >
        {{alertContent}}
  </v-alert>
Then we add retrieveMessaging() in the mounted() life cycle hook:
  mounted() {
    db.once('value', (notes) => {
      notes.forEach((note) => {
        this.pages.push({
          title: note.child('title').val(),
          content: note.child('content').val(),
          ref: note.ref
        })
      })
    });
    this.retrieveMessaging();
  },

The next thing we need to do is create a service worker that handles messages in the background. To do this, we need to make a firebase-messaging-sw.js file (which is the name to use if you are going to use the Firebase library) at the same level as index.html. In index.html, we implement push notification handling. To do this, we need to modify some files.

vue.config.js
module.exports = {
    pwa: {
        // Configure the Workbox plug-in.
        workboxPluginMode: 'InjectManifest',
        workboxOptions: {
            // swSrc is required in InjectManifest mode.
            swSrc: 'src/firebase-messaging-sw.js',
        }
    }
}
In src/registerServiceWorker.js:
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
  register(`${process.env.BASE_URL}firebase-messaging-sw.js`, {
    ready () {
      /* console.log(
        'App is being served from cache by a service worker. ' +
        'For more details, visit https://goo.gl/AFskqB'
      ); */
    },
    registered () {
      // console.log('Service worker has been registered.')
    },
    cached () {
      // console.log('Content has been cached for offline use.')
    },
    updatefound () {
      // console.log('New content is downloading.')
    },
    updated () {
      // console.log('New content is available; please refresh.')
    },
    offline () {
      // console.log('No Internet connection found. App is running in offline mode.')
    },
    error (error) {
      console.error('Error during service worker registration:', error)
    }
  })
}
Now we need to create a new firebase-messaging-sw.js file:
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
importScripts('https://www.gstatic.com/firebasejs/5.5.6/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/5.5.6/firebase-messaging.js');
firebase.initializeApp({
   'messagingSenderId': '217988350403'
 });
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here.
  var notificationTitle = 'Background Message Title';
  var notificationOptions = {
    body: 'Background Message body.',
    icon: '/icons/icon-128x128.png'
  };
  return self.registration.showNotification(notificationTitle,
    notificationOptions);
});

With this code, we have added the Workbox offline features and the Firebase messaging background features to our app. Also, note that we are using senderId in the firebase.initializeApp() method.

Run ning the App

Okay. Now we need to run
$npm run build
$serve -s dist
Go to http://localhost:5000. You should see something similar to what is shown in Figure 8-5.
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig5_HTML.jpg
Figure 8-5

Ask for permission in VueNoteApp

After we allow notifications, the user token for this device shows up (Figure 8-6).
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig6_HTML.jpg
Figure 8-6

Device ID token

The thing here is that we need a server to send us push notifications, but we can fake this with a curl script. To test that the information is being sent from the terminal (in my case, I use a Mac), you can simulate a message with the following command:
#!/bin/bash
curl https://fcm.googleapis.com/fcm/send
     -H "Content-Type: application/json"
     -H "Authorization: key=XXXXX"
     -d '{ "notification": {"title": "Push", "body": "This is a Foreground message.", "click_action" : "https://www.localhost.com"},"to" : "YYYYYY"}'
We simply have to change XXXXX using the server configuration key we found in the Cloud Messaging tab in the Project settings of our project in Firebase. We must also change YYYYYY using the user’s token. We get the user’s token from the page console.log. Now, every time we execute the script, we send a push notification to that client (Figure 8-7).
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig7_HTML.jpg
Figure 8-7

Getting a message in VueNoteApp

Figure 8-8 shows the notifications in the app.
../images/483082_1_En_8_Chapter/483082_1_En_8_Fig8_HTML.jpg
Figure 8-8

Getting a push notification in VueNoteApp

In the future, the push notification must be sent by a back-end server, but we are already handling the push service protocol and the notification.

You can go there from the repo (https://github.com/carlosrojaso/appress-book-pwa) with
$git checkout PushNotifications
If you are using a Mac, you can find test.push.sh script to make it more easy to simulate a push notification. Update with your server key and user token information and run
$./test.push.sh

Summary

Having push notifications allows us to interact with our users even when they have closed our app. In this chapter, we used various methods to generate a notification permission and to allow push notifications to appear in our PWA.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.6.194