PWA Learning and Practice series articles have been compiled into gitbook-PWA Learning Handbook, and the text has been synchronized to learning-PWA-ebook. Please indicate the author and source of reprint.

This is the seventh article in the PWA Learning & Practice series.

PWA, as one of the hottest technology concepts at present, has great significance for improving the security, performance and experience of Web applications, and is worth our understanding and learning. If you are interested in PWA, please pay attention to the PWA Learning and Practice series.

The code in this article can be found on the Notification branch of learning-PWA (note the switch to the Notification branch after git clone).

1. The introduction

In my fifth article, “Pushing Server messages on the Web,” I showed you how to Push server messages using the Push API. When it comes to Push, there is another API closely associated with Push — the Notification API. It allows us to display a message prompt “off site” :

Even when you switch to another Tab, you can remind users to return to your site quickly; Even when the user is away from the current site, the system can still receive a reminder message, and can quickly open your site through the message reminder.

The functionality of Notification itself is not coupled to Push, and you can simply use the Notification API or the Push API to build some functionality of your Web App. Therefore, this article will first show you how to use the Notification API. Then, as a great companion to Notification, I’ll show you how to combine Push and Notification.

2. Use the Notification API

In this second section, we first look at how to use Notification functionality in isolation. The Notification API is much more concise and understandable than the Push functionality in Article 5.

2.1. Obtain the notification permission

First, the user’s authorization is required to invoke the message alert API.

Before the related API call Notification, need to use the static methods on the Notification object Notification. RequestPermission () to obtain authorization. Because Notification. RequestPermission () in some browsers will receive a callback function (Notification. RequestPermission (the callback)) as a parameter, Other browser versions return a promise, so wrap the method as a promise call:

// index.js
function askPermission() {
    return new Promise(function (resolve, reject) {
        var permissionResult = Notification.requestPermission(function (result) {
            resolve(result);
        });
  
        if (permissionResult) {
            permissionResult.then(resolve, reject);
        }
    }).then(function (permissionResult) {
        if(permissionResult ! = ='granted') {
            throw new Error('We weren\'t granted permission.'); }}); } registerServiceWorker('./sw.js').then(function (registration) {
    return Promise.all([
        registration,
        askPermission()
    ])
 })
Copy the code

We created a askPermission () method to unify Notification. RequestPermission () call form, and in the Service Worker call this method after the completion of registration. Call Notification. RequestPermission () to obtain permissionResult possible values are:

  • Denied: The user rejected the notification
  • Granted: The user allowed the notification to be displayed
  • Default: The browser behaves the same as if denied because the user’s choice is not known

Chrome, can be in chrome: / / Settings/content/notifications in the notification Settings and management.

2.2. Set your reminders

After get the user authorization, we can through registration. ShowNotification has been alerted to () method.

When we have registered the Service Worker, the then method’s callback receives a registration parameter, which can be triggered by calling the showNotification() method on it:

// index.js
registerServiceWorker('./sw.js').then(function (registration) {
    return Promise.all([
        registration,
        askPermission()
    ])
}).then(function (result) {
    var registration = result[0];
    /* ===== add notification function ====== */
    document.querySelector('#js-notification-btn').addEventListener('click'.function () {
        var title = 'PWA as You Learn ';
        var options = {
            body: 'I invite you to study with me'.icon: '/img/icons/book-128.png'.actions: [{
                action: 'show-book'.title: 'Go and see'
            }, {
                action: 'contact-me'.title: 'Contact me'}].tag: 'pwa-starter'.renotify: true
        };
        registration.showNotification(title, options);
    });
    / * = = = = = = = = = = = = = = = = = = = = = = = * /
})
Copy the code

Above this code for the button on the page to add a click event listener: when clicked, call registration. ShowNotification () method to display a message to remind, the method takes two parameters: the title and option. Title is used to set the main title of the reminder, and option contains some other Settings.

  • Body: The content of the reminder
  • Icon: indicates a reminder icon
  • Actions: Reminders can contain some custom actions
  • Tag: This is equivalent to an ID that identifies the specific Notification that can be manipulated
  • Renotify: Indicates whether repeated notification is allowed. The default value is false. When repeated reminders are not allowed, the Notification for the same tag is displayed only once

Note that support for the option property varies from browser to browser. Some properties are not supported in some browsers.

2.3. Capture user clicks

In the previous section, we added reminders to the Web App. Click the “Reminder” button in the page, and the system will pop up a reminder box and display the relevant reminder message.

More often than not, however, we don’t just want to present limited information, we want to guide the user to interact. For example, suggest a new book and let the user click to read it or buy it. The reminder box we set up in the last part contains two button options of “go and see” and “contact me”. So how can we capture the user’s click operation and know which one the user clicked? This section will show you how to do it.

Remember the actions we defined in the last section?

... actions: [{action: 'show-book'.title: 'Go and see'
    }, {
    action: 'contact-me'.title: 'Contact me'}]...Copy the code

To be able to respond to user clicks on the reminder box, we need to listen for the NotificationClick event in the Service Worker. In the event callback function we can get information about the click:

// sw.js
self.addEventListener('notificationclick'.function (e) {
    var action = e.action;
    console.log(`action tag: ${e.notification.tag}`.`action: ${action}`);
    
    switch (action) {
        case 'show-book':
            console.log('show-book');
            break;
        case 'contact-me':
            console.log('contact-me');
            break;
        default:
            console.log('Unprocessed action:${e.action}`);
            action = 'default';
            break;
    }
    e.notification.close();
});
Copy the code

The value obtained by e.action is the action we defined in showNotification(). Therefore, e.action lets you know which action option the user clicked. Note that notificationClick is also triggered when the user clicks on the reminder itself, but does not contain any action value, so put it in the default default action in the code.

Now try it out and we can capture user clicks on different options. When clicked, different output is displayed in the Console.

2.4. Service Worker communicates with client

So far, we have been able to show the user a reminder without any problems and capture exactly what the user did after the reminder was used. However, the most important step is missing — triggering different interactions for different operations. For example,

  • Clicking on the reminder itself will bring up an introduction to the book;
  • Clicking “Take a look” shows the user the details of the book;
  • Clicking “Contact me” sends an email to the app manager and so on.

Here’s an important point: we capture user actions in the Service Worker, but we need to trigger them in the client (by client we mean the scripting environment of the front page) (invoke page methods/jump pages…). . Therefore, this requires the Service Worker to communicate with the client. Communication consists of the following two parts:

  1. Using the Worker in the Service WorkerpostMessage()Method to tell client:
// sw.js
self.addEventListener('notificationclick'.function (e) {...// Omit the previous section
    
    e.waitUntil(
        // Get all clients
        self.clients.matchAll().then(function (clients) {
            if(! clients || clients.length ===0) {
                return;
            }
            clients.forEach(function (client) {
                // Use postMessage to communicateclient.postMessage(action); }); })); });Copy the code
  1. Listen in clientmessageEvent, judgmentdataTo perform different operations:
// index.js
navigator.serviceWorker.addEventListener('message'.function (e) {
    var action = e.data;
    console.log(`receive post-message from sw, action is '${e.data}'`);
    switch (action) {
        case 'show-book':
            location.href = 'https://book.douban.com/subject/20515024/';
            break;
        case 'contact-me':
            location.href = 'mailto:[email protected]';
            break;
        default:
            document.querySelector('.panel').classList.add('show');
            break; }});Copy the code

When the user clicks the notification, we communicate the action to the client via postMessage() in the NotificationClick listener. Then listen for message events in the client and perform different actions based on action (E.ata) (jump to book details page/send mail/display introduction panel).

At this point, a relatively simple and complete Notification function is complete.

However, the current message alert still has some limitations. For example, only during a user’s visit to the site does the user have a chance to trigger an alert. As stated at the beginning of this article, the combination of Push and Notification will help us build a powerful Push and Notification feature. Let’s look at a simple combination of them.

3. Message push and reminder

At the end of article 5, Server-side Pushing on the Web, we handle server-side pushing by listening for push events:

// sw.js
self.addEventListener('push'.function (e) {
    var data = e.data;
    if (e.data) {
        data = data.json();
        console.log(The data for 'push 'is:, data);
        self.registration.showNotification(data.text);        
    } 
    else {
        console.log('Push doesn't have any data'); }});Copy the code

Simply modify the above code to combine with our reminder feature in this article:

// sw.js
self.addEventListener('push'.function (e) {
    var data = e.data;
    if (e.data) {
        data = data.json();
        console.log(The data for 'push 'is:, data);
        var title = 'PWA as You Learn ';
        var options = {
            body: data,
            icon: '/img/icons/book-128.png'.image: '/img/icons/book-521.png'.// no effect
            actions: [{
                action: 'show-book'.title: 'Go and see'
            }, {
                action: 'contact-me'.title: 'Contact me'}].tag: 'pwa-starter'.renotify: true
        };
        self.registration.showNotification(title, options);        
    } 
    else {
        console.log('Push doesn't have any data'); }});Copy the code

Use Push to Push information to the user, and call the Notification API directly in the Service Worker to display a reminder box for the information. In this way, even when users close the Web App, they can still receive a reminder, similar to message push and reminder in Native.

We can also make this feature more extensive. Since users can still get alerts when they close the site, some more powerful features have been added:

  • When the user switches to another Tab, clicking the reminder will immediately return to the site Tab;
  • When the user does not open the website, click on the reminder can directly open the website.
// sw.js
self.addEventListener('notificationclick'.function (e) {
    var action = e.action;
    console.log(`action tag: ${e.notification.tag}`.`action: ${action}`);
    
    switch (action) {
        case 'show-book':
            console.log('show-book');
            break;
        case 'contact-me':
            console.log('contact-me');
            break;
        default:
            console.log('Unprocessed action:${e.action}`);
            action = 'default';
            break;
    }
    e.notification.close();

    e.waitUntil(
        // Get all clients
        self.clients.matchAll().then(function (clients) {
            if(! clients || clients.length ===0) {
                // If no client exists, open this website
                self.clients.openWindow && self.clients.openWindow('http://127.0.0.1:8085');
                return;
            }
            // Switch to the TAB of the site
            clients[0].focus && clients[0].focus();
            clients.forEach(function (client) {
                // Use postMessage to communicateclient.postMessage(action); }); })); });Copy the code

Notice that the first line opens the site when it is closed, and the second line automatically switches to the site’s TAB when a TAB is present.

self.clients.openWindow && self.clients.openWindow('http://127.0.0.1:8085');

clients[0].focus && clients[0].focus();
Copy the code

4. Web Notification in MacOS Safari

Take a look at the compatibility of Web Notification:

Currently, mobile browsers do not support this feature. Safari on Mac OS does support this feature, though it is called in a slightly different way. Using Web registration Notification is not call in safari. ShowNotification () method, but you need to create a Notification object.

// index.js...document.querySelector('#js-notification-btn').addEventListener('click'.function () {
    var title = 'PWA as You Learn ';
    var options = {
        body: 'I invite you to study with me'.icon: '/img/icons/book-128.png'.actions: [{
            action: 'show-book'.title: 'Go and see'
        }, {
            action: 'contact-me'.title: 'Contact me'}].tag: 'pwa-starter'.renotify: true
    };
    // registration.showNotification(title, options);

    // Use the Notification constructor to create a reminder box
    / / not registration. ShowNotification () method
    var notification = newNotification(title, options); }); ...Copy the code

The Notification object inherits from the EventTarget interface, so safari needs to add a listener for the click event to trigger the interaction of the reminder box:

// index.js
notification.addEventListener('click'.function (e) {
    document.querySelector('.panel').classList.add('show');
});
Copy the code

Examples of this feature can be found in learn-pwa/ Notify4Safari.

5. Write at the end

Web Notification is a very powerful API that, especially when combined with Push, brings Native rich capabilities to WebApps.

All of the code examples in this article can be found at learn-pwa/ Notification.

If you like or want to learn more about PWA, please feel free to follow me and follow the PWA Learning & Practice series. I will summarize the questions and technical points I have encountered in the process of learning PWA, and practice with everyone through actual codes.

So far, we’ve covered the basics of Manifest, offline caching, message push, message reminders, Debug, and more. In the next article, we’ll continue to learn about one of the most important features of PWA — background synchronization.

PWA Learning and Practice series

  • Start your PWA learning journey in 2018
  • Learn to Use Manifest to Make your WebApp More “Native”
  • Make your WebApp available offline from today
  • Article 4: TroubleShooting: TroubleShooting FireBase Login Authentication Failures
  • Keep in touch with Your Users: The Web Push feature
  • How to Debug? Debug your PWA in Chrome
  • Enhanced Interaction: Using the Notification API for reminders (this article)
  • Chapter 8: Background Data Synchronization using Service Worker
  • Chapter nine: Problems and solutions in PWA practice
  • Resource Hint – Improving page loading performance and Experience
  • Part 11: Learning offline Strategies from workbox

The resources

  • MDN: notification
  • MDN: ServiceWorkerRegistration.showNotification()
  • MDN: WindowClient
  • MDN: Clients
  • WWDC2013