ก่อนอื่น เราขออภัยสำหรับชื่อที่แย่มาก แต่เราอดไม่ได้จริงๆ
ใน Chrome 44 จะมีการเพิ่ม Notfication.data และ ServiceWorkerRegistration.getNotifications() เพื่อเปิดโอกาสและลดความซับซ้อนของกรณีการใช้งานทั่วไปบางอย่างเมื่อจัดการกับการแจ้งเตือนด้วยข้อความ 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() คุณจะ "ยุบ" การแจ้งเตือนได้หากมีการแสดงการแจ้งเตือนอยู่แล้ว ซึ่งจะช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีขึ้นมาก
โค้ดที่ใช้ทำเช่นนี้ค่อนข้างง่าย ในเหตุการณ์ Push ให้เรียกใช้ ServiceWorkerRegistration.getNotifications() เพื่อรับอาร์เรย์ของ Notification ปัจจุบัน จากนั้นตัดสินใจเลือกลักษณะการทำงานที่เหมาะสม ไม่ว่าจะเป็นการยุบการแจ้งเตือนทั้งหมดหรือใช้ 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)
จากนั้นเราจะตรวจสอบการแจ้งเตือนที่มองเห็นได้และดูว่ามีจํานวนการแจ้งเตือนที่เชื่อมโยงกับการแจ้งเตือนนั้นหรือไม่ และเพิ่มจํานวนตามนั้น วิธีนี้ช่วยให้เราชี้แจงได้ว่ามีข้อความที่ยังไม่อ่าน 3 รายการเมื่อข้อความ Push ใหม่มาถึง หากมีการแจ้งเตือน 1 รายการที่แจ้งให้ผู้ใช้ทราบว่ามีข้อความที่ยังไม่อ่าน 2 รายการ
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) ตัวเลือกนี้จะช่วยให้คุณปรับแต่งรูปแบบการสั่นที่จะใช้เมื่อแสดงการแจ้งเตือนได้
รูปแบบการสั่นอาจเป็นอาร์เรย์ของตัวเลขหรือตัวเลขเดียวซึ่งระบบจะถือว่าเป็นอาร์เรย์ของตัวเลข 1 รายการ ค่าในอาร์เรย์แสดงเวลาเป็นมิลลิวินาที โดยดัชนีคู่ (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();
}