การแจ้งให้คุณทราบเกี่ยวกับการเปลี่ยนแปลงการแจ้งเตือน

ก่อนอื่น เราต้องขออภัยสำหรับชื่อที่แย่ขนาดนี้ แต่เราไม่อาจทำได้

ใน Chrome 44 จะมีการเพิ่ม Notfication.data และ ServiceWorkerRegistration.getNotifications() เพื่อเปิดโอกาสและลดความซับซ้อนของ Use Case ทั่วไปบางอย่างเมื่อจัดการกับการแจ้งเตือนด้วยข้อความ Push

ข้อมูลการแจ้งเตือน

Notification.data ช่วยให้คุณเชื่อมโยงออบเจ็กต์ JavaScript กับ Notification ได้

สรุปก็คือ เมื่อได้รับข้อความ Push คุณจะสร้างการแจ้งเตือนพร้อมข้อมูลบางอย่างได้ จากนั้นในเหตุการณ์การคลิกการแจ้งเตือน คุณจะรับการแจ้งเตือนที่มีการคลิกและรับข้อมูลของการแจ้งเตือนนั้นได้

เช่น การสร้างออบเจ็กต์ข้อมูลและเพิ่มลงในตัวเลือกการแจ้งเตือน ดังนี้

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';
    var data = {
    doge: {
        wow: 'such amaze notification data'
    }
    };

    event.waitUntil(
    self.registration.showNotification(title, {
        body: body,
        icon: icon,
        tag: tag,
        data: data
    })
    );
});

ซึ่งหมายความว่าเราจะรับข้อมูลในเหตุการณ์ notificationclick ได้ดังนี้

self.addEventListener('notificationclick', function(event) {
    var doge = event.notification.data.doge;
    console.log(doge.wow);
});

ก่อนหน้านี้คุณต้องเก็บข้อมูลไว้ใน IndexDB หรือใส่ข้อมูลไว้ที่ท้าย URL ของไอคอน

ServiceWorkerRegistration.getNotifications()

คำขอหนึ่งที่พบบ่อยจากนักพัฒนาซอฟต์แวร์ที่ทำงานเกี่ยวกับข้อความ Push คือให้ควบคุมการแจ้งเตือนที่แสดงได้ดียิ่งขึ้น

ตัวอย่าง Use Case อาจเป็นแอปพลิเคชันแชทที่ผู้ใช้ส่งข้อความหลายรายการและผู้รับแสดงการแจ้งเตือนหลายรายการ ตามหลักการแล้วเว็บแอปจะสังเกตเห็นว่าคุณมีการแจ้งเตือนหลายรายการที่ยังไม่ได้ดูและยุบรวมไว้ในการแจ้งเตือนเดียว

หากไม่มี getNotifications() สิ่งที่คุณทำได้ดีที่สุดคือแทนที่การแจ้งเตือนก่อนหน้าด้วยข้อความล่าสุด เมื่อใช้ getNotifications() คุณจะ "ยุบ" การแจ้งเตือนได้หากมีการแสดงการแจ้งเตือนอยู่แล้ว ซึ่งจะช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีขึ้นมาก

ตัวอย่างการจัดกลุ่มการแจ้งเตือนไว้ด้วยกัน

โค้ดที่ใช้ทำเช่นนี้ค่อนข้างง่าย ภายในเหตุการณ์พุช ให้เรียกใช้ ServiceWorkerRegistration.getNotifications() เพื่อรับอาร์เรย์ของการแจ้งเตือนปัจจุบันและจากตรงนั้นให้ตัดสินใจเกี่ยวกับการทำงานที่เหมาะสม ไม่ว่าจะเป็นการย่อการแจ้งเตือนทั้งหมดหรือการใช้ Notification.tag

function showNotification(title, body, icon, data) {
    var notificationOptions = {
    body: body,
    icon: icon ? icon : 'images/touch/chrome-touch-icon-192x192.png',
    tag: 'simple-push-demo-notification',
    data: data
    };

    self.registration.showNotification(title, notificationOptions);
    return;
}

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    // Since this is no payload data with the first version
    // of Push notifications, here we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
            response.status);
        // Throw an error so the promise is rejected and catch() is executed
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        var title = 'You have a new message';
        var message = data.message;
        var icon = 'images/notification-icon.png';
        var notificationTag = 'chat-message';

        var notificationFilter = {
            tag: notificationTag
        };
        return self.registration.getNotifications(notificationFilter)
            .then(function(notifications) {
            if (notifications && notifications.length > 0) {
                // Start with one to account for the new notification
                // we are adding
                var notificationCount = 1;
                for (var i = 0; i < notifications.length; i++) {
                var existingNotification = notifications[i];
                if (existingNotification.data &&
                    existingNotification.data.notificationCount) {
                    notificationCount +=
existingNotification.data.notificationCount;
                } else {
                    notificationCount++;
                }
                existingNotification.close();
                }
                message = 'You have ' + notificationCount +
                ' weather updates.';
                notificationData.notificationCount = notificationCount;
            }

            return showNotification(title, message, icon, notificationData);
            });
        });
    }).catch(function(err) {
        console.error('Unable to retrieve data', err);

        var title = 'An error occurred';
        var message = 'We were unable to get the information for this ' +
        'push message';

        return showNotification(title, message);
    })
    );
});

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event);

    if (Notification.prototype.hasOwnProperty('data')) {
    console.log('Using Data');
    var url = event.notification.data.url;
    event.waitUntil(clients.openWindow(url));
    } else {
    event.waitUntil(getIdb().get(KEY_VALUE_STORE_NAME,
event.notification.tag).then(function(url) {
        // At the moment you cannot open third party URL's, a simple trick
        // is to redirect to the desired URL from a URL on your domain
        var redirectUrl = '/redirect.html?redirect=' +
        url;
        return clients.openWindow(redirectUrl);
    }));
    }
});

สิ่งแรกที่ไฮไลต์ด้วยข้อมูลโค้ดนี้คือเรากรองการแจ้งเตือนโดยการส่งออบเจ็กต์ตัวกรองไปยัง getNotifications() ซึ่งหมายความว่าเราจะรับรายการการแจ้งเตือนสำหรับแท็กหนึ่งๆ ได้ (ในตัวอย่างนี้สําหรับการสนทนานั้นๆ)

var notificationFilter = {
    tag: notificationTag
};
return self.registration.getNotifications(notificationFilter)

จากนั้นเราจะตรวจสอบการแจ้งเตือนที่มองเห็นได้และดูว่ามีจํานวนการแจ้งเตือนที่เชื่อมโยงกับการแจ้งเตือนนั้นหรือไม่ และเพิ่มจํานวนตามนั้น ด้วยวิธีนี้ หากมีการแจ้งเตือน 1 รายการที่บอกผู้ใช้ว่ามีข้อความที่ยังไม่อ่าน 2 ข้อความ เราอยากจะชี้ให้เห็นว่ามีข้อความที่ยังไม่ได้อ่าน 3 ข้อความ เมื่อมีข้อความ Push ใหม่เข้ามา

var notificationCount = 1;
for (var i = 0; i < notifications.length; i++) {
    var existingNotification = notifications[i];
    if (existingNotification.data && existingNotification.data.notificationCount) {
    notificationCount += existingNotification.data.notificationCount;
    } else {
    notificationCount++;
    }
    existingNotification.close();
}

สิ่งที่ควรทราบคือคุณต้องเรียกใช้ close() ในการแจ้งเตือนเพื่อให้แน่ใจว่าระบบนำการแจ้งเตือนออกจากรายการการแจ้งเตือนแล้ว นี่เป็นข้อบกพร่องใน Chrome เนื่องจากระบบจะแทนที่การแจ้งเตือนแต่ละรายการด้วยรายการถัดไปเนื่องจากมีการใช้แท็กเดียวกัน ขณะนี้ การเปลี่ยนทดแทนนี้ยังไม่แสดงในอาร์เรย์ที่แสดงผลจาก getNotifications()

นี่เป็นเพียงตัวอย่างหนึ่งของ getNotifications() ดังที่คุณพอจะนึกออก API นี้ก็จะเปิดกรณีการใช้งานอื่นๆ มากมาย

NotificationOptions.vibrate

ใน Chrome 45 คุณสามารถระบุรูปแบบการสั่นเมื่อสร้างการแจ้งเตือนได้ ในอุปกรณ์ที่รองรับ Vibration API (ปัจจุบันมีเฉพาะ Chrome สำหรับ Android) ตัวเลือกนี้จะช่วยให้คุณปรับแต่งรูปแบบการสั่นที่จะใช้เมื่อแสดงการแจ้งเตือนได้

รูปแบบการสั่นอาจเป็นอาร์เรย์ของตัวเลข หรือตัวเลขเดี่ยวก็ได้ ซึ่งจะถือว่าเป็นอาร์เรย์ของตัวเลขหนึ่ง ค่าในอาร์เรย์แสดงเวลาเป็นมิลลิวินาที โดยดัชนีคู่ (0, 2, 4, ...) หมายถึงระยะเวลาในการสั่น และดัชนีคี่หมายถึงระยะเวลาในการหยุดชั่วคราวก่อนการสั่นครั้งถัดไป

self.registration.showNotification('Buzz!', {
    body: 'Bzzz bzzzz',
    vibrate: [300, 100, 400] // Vibrate 300ms, pause 100ms, then vibrate 400ms
});

คำขอฟีเจอร์ทั่วไปที่เหลืออยู่

คำขอฟีเจอร์ทั่วไปอย่างหนึ่งจากนักพัฒนาซอฟต์แวร์คือ ความสามารถในการปิดการแจ้งเตือนหลังจากช่วงระยะเวลาหนึ่ง หรือความสามารถในการส่งข้อความ Push โดยมีจุดประสงค์แค่การปิดการแจ้งเตือนหากมีการแจ้งเตือนแสดงอยู่

ขณะนี้คุณไม่สามารถดำเนินการดังกล่าวได้และไม่มีข้อมูลในข้อกำหนดที่อนุญาต :( แต่ทีมวิศวกรของ Chrome ทราบถึงกรณีการใช้งานนี้

การแจ้งเตือนของ Android

คุณสร้างการแจ้งเตือนด้วยรหัสต่อไปนี้ในเดสก์ท็อปได้

new Notification('Hello', {body: 'Yay!'});

Android ไม่เคยรองรับการดำเนินการนี้เนื่องจากข้อจำกัดของแพลตฟอร์ม โดยเฉพาะอย่างยิ่ง Chrome ไม่รองรับการเรียกกลับในออบเจ็กต์การแจ้งเตือน เช่น onclick แต่จะใช้ในเดสก์ท็อปเพื่อแสดงการแจ้งเตือนสำหรับเว็บแอปที่เคยเปิดไว้

เหตุผลที่เราพูดถึงเรื่องนี้คือ เดิมทีการตรวจหาฟีเจอร์อย่างง่าย เช่น ด้านล่างนี้ จะช่วยให้คุณรองรับเดสก์ท็อปและไม่ทำให้เกิดข้อผิดพลาดใน Android

if (!'Notification' in window) {
    // Notifications aren't supported
    return;
}

อย่างไรก็ตาม ตอนนี้ Chrome สำหรับ Android รองรับข้อความ Push แล้ว ซึ่งระบบจะสร้างการแจ้งเตือนจาก ServiceWorker ได้ แต่ไม่สามารถสร้างจากหน้าเว็บได้ ซึ่งหมายความว่าการตรวจหาฟีเจอร์นี้ไม่เหมาะสมอีกต่อไป หากพยายามสร้างการแจ้งเตือนใน Chrome สำหรับ Android คุณจะได้รับข้อความแสดงข้อผิดพลาดนี้

_Uncaught TypeError: Failed to construct 'Notification': Illegal constructor.
Use ServiceWorkerRegistration.showNotification() instead_

วิธีที่ดีที่สุดในการตรวจหาฟีเจอร์สำหรับ Android และเดสก์ท็อปในขณะนี้คือการดำเนินการต่อไปนี้

    function isNewNotificationSupported() {
        if (!window.Notification || !Notification.requestPermission)
            return false;
        if (Notification.permission == 'granted')
            throw new Error('You must only call this \*before\* calling
    Notification.requestPermission(), otherwise this feature detect would bug the
    user with an actual notification!');
        try {
            new Notification('');
        } catch (e) {
            if (e.name == 'TypeError')
                return false;
        }
        return true;
    }

ซึ่งจะใช้ได้ดังนี้

    if (window.Notification && Notification.permission == 'granted') {
        // We would only have prompted the user for permission if new
        // Notification was supported (see below), so assume it is supported.
        doStuffThatUsesNewNotification();
    } else if (isNewNotificationSupported()) {
        // new Notification is supported, so prompt the user for permission.
        showOptInUIForNotifications();
    }