หากถามนักพัฒนาแอปว่าฟีเจอร์ใดของอุปกรณ์เคลื่อนที่ที่ขาดหายไปจากเว็บ ฟีเจอร์ Push Notification มักจะติดอันดับต้นๆ เสมอ
ข้อความ Push ช่วยให้ผู้ใช้เลือกรับการอัปเดตที่ตรงเวลาจากเว็บไซต์ที่ตนชื่นชอบ และช่วยให้คุณดึงดูดผู้ใช้ให้กลับมามีส่วนร่วมอีกครั้งได้อย่างมีประสิทธิภาพด้วยเนื้อหาที่ดึงดูดใจและปรับให้เหมาะกับผู้ใช้
ตั้งแต่ Chrome เวอร์ชัน 42 เป็นต้นไป Push API และ Notification API พร้อมให้บริการแก่นักพัฒนาซอฟต์แวร์แล้ว
Push API ใน Chrome อาศัยเทคโนโลยีหลายอย่างด้วยกัน ซึ่งรวมถึงไฟล์ Manifest ของเว็บแอปและ Service Worker ในโพสต์นี้ เราจะพูดถึงเทคโนโลยีแต่ละอย่างเหล่านี้ แต่ขอพูดถึงเฉพาะข้อมูลขั้นต่ำเท่านั้นเพื่อเริ่มต้นใช้งานการรับส่งข้อความ Push หากต้องการทําความเข้าใจฟีเจอร์อื่นๆ ของไฟล์ Manifest และความสามารถแบบออฟไลน์ของ Service Worker ให้ดียิ่งขึ้น โปรดดูลิงก์ด้านบน
นอกจากนี้ เราจะดูสิ่งที่จะเพิ่มลงใน API ใน Chrome เวอร์ชันต่อๆ ไป และสุดท้ายจะมีคําถามที่พบบ่อย
การใช้การรับส่งข้อความ Push สําหรับ Chrome
ส่วนนี้จะอธิบายขั้นตอนแต่ละขั้นตอนที่คุณต้องดำเนินการเพื่อรองรับการรับส่งข้อความ Push ในเว็บแอป
ลงทะเบียน Service Worker
จำเป็นต้องมี Service Worker เพื่อใช้ข้อความ Push สำหรับเว็บ เหตุผลคือเมื่อได้รับข้อความ Push เบราว์เซอร์สามารถเริ่ม Service Worker ซึ่งทำงานในเบื้องหลังโดยที่ไม่ต้องเปิดหน้าเว็บ และส่งเหตุการณ์เพื่อให้คุณตัดสินใจว่าจะจัดการข้อความ Push นั้นอย่างไร
ด้านล่างนี้คือตัวอย่างวิธีลงทะเบียน Service Worker ในเว็บแอป เมื่อลงทะเบียนเสร็จเรียบร้อยแล้ว เราจะเรียกใช้ initialiseState() ซึ่งเราจะอธิบายในอีกไม่ช้า
var isPushEnabled = false;
…
window.addEventListener('load', function() {
var pushButton = document.querySelector('.js-push-button');
pushButton.addEventListener('click', function() {
if (isPushEnabled) {
unsubscribe();
} else {
subscribe();
}
});
// Check that service workers are supported, if so, progressively
// enhance and add push messaging support, otherwise continue without it.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(initialiseState);
} else {
console.warn('Service workers aren\'t supported in this browser.');
}
});
แฮนเดิลการคลิกปุ่มจะสมัครหรือยกเลิกการสมัครรับข้อความ Push ของผู้ใช้ isPushEnabled คือตัวแปรส่วนกลางที่ติดตามว่าขณะนี้มีการสมัครรับข้อความ Push หรือไม่ ระบบจะใช้ตัวแปรเหล่านี้ตลอดทั้งข้อมูลโค้ด
จากนั้นเราจะตรวจสอบว่าระบบรองรับ Service Worker ก่อนที่จะลงทะเบียนservice-worker.js
ไฟล์ซึ่งมีตรรกะสำหรับจัดการข้อความ Push ในส่วนนี้ เราเพียงแค่บอกเบราว์เซอร์ว่าไฟล์ JavaScript นี้เป็น Service Worker สำหรับเว็บไซต์ของเรา
ตั้งค่าสถานะเริ่มต้น
เมื่อลงทะเบียน Service Worker แล้ว เราจะต้องตั้งค่าสถานะของ UI
ผู้ใช้จะคาดหวัง UI ที่ใช้งานง่ายเพื่อเปิดหรือปิดใช้ข้อความ Push สําหรับเว็บไซต์ของคุณ และคาดหวังว่า UI จะอัปเดตอยู่เสมอเมื่อมีการเปลี่ยนแปลง กล่าวคือ หากผู้ใช้เปิดใช้ข้อความ Push สําหรับเว็บไซต์ของคุณ แล้วออกจากเว็บไซต์ไป 1 สัปดาห์ต่อมา UI ควรไฮไลต์ว่าเปิดใช้ข้อความ Push อยู่แล้ว
คุณสามารถดูหลักเกณฑ์ UX ในเอกสารนี้ ส่วนในบทความนี้เราจะเน้นที่ด้านเทคนิค
ณ จุดนี้ คุณอาจคิดว่ามีสถานะเพียง 2 สถานะเท่านั้น ได้แก่ เปิดใช้หรือปิดใช้ อย่างไรก็ตาม ยังมีสถานะอื่นๆ เกี่ยวกับการแจ้งเตือนที่คุณต้องพิจารณาด้วย
เรามี API หลายรายการที่ต้องตรวจสอบก่อนที่จะเปิดใช้ปุ่ม และหากรองรับทุกอย่างแล้ว เราจะเปิดใช้ UI และตั้งค่าสถานะเริ่มต้นเพื่อระบุว่ามีการสมัครรับข้อความ Push หรือไม่
เนื่องจากการตรวจสอบส่วนใหญ่เหล่านี้ส่งผลให้ UI ถูกปิดใช้ คุณจึงควรตั้งค่าสถานะเริ่มต้นเป็น "ปิดใช้" นอกจากนี้ ยังช่วยหลีกเลี่ยงความสับสนในกรณีที่ JavaScript ของหน้าเว็บมีปัญหา เช่น ดาวน์โหลดไฟล์ JS ไม่ได้ หรือผู้ใช้ปิดใช้ JavaScript
<button class="js-push-button" disabled>
Enable Push Messages
</button>
สถานะเริ่มต้นนี้ช่วยให้เราทําการตรวจสอบที่ระบุไว้ข้างต้นในเมธอด initialiseState()
ได้ เช่น หลังจากลงทะเบียน Service Worker แล้ว
// Once the service worker is registered set the initial state
function initialiseState() {
// Are Notifications supported in the service worker?
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
console.warn('Notifications aren\'t supported.');
return;
}
// Check the current Notification permission.
// If its denied, it's a permanent block until the
// user changes the permission
if (Notification.permission === 'denied') {
console.warn('The user has blocked notifications.');
return;
}
// Check if push messaging is supported
if (!('PushManager' in window)) {
console.warn('Push messaging isn\'t supported.');
return;
}
// We need the service worker registration to check for a subscription
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
// Do we already have a push message subscription?
serviceWorkerRegistration.pushManager.getSubscription()
.then(function(subscription) {
// Enable any UI which subscribes / unsubscribes from
// push messages.
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = false;
if (!subscription) {
// We aren't subscribed to push, so set UI
// to allow the user to enable push
return;
}
// Keep your server in sync with the latest subscriptionId
sendSubscriptionToServer(subscription);
// Set your UI to show they have subscribed for
// push messages
pushButton.textContent = 'Disable Push Messages';
isPushEnabled = true;
})
.catch(function(err) {
console.warn('Error during getSubscription()', err);
});
});
}
ภาพรวมคร่าวๆ ของขั้นตอนเหล่านี้มีดังนี้
- เราตรวจสอบว่า
showNotification
พร้อมใช้งานใน ServiceWorkerRegistration prototype หากไม่มี แสดงว่าเราไม่สามารถแสดงการแจ้งเตือนจาก Service Worker ได้เมื่อได้รับข้อความ Push - เราจะตรวจสอบว่า
Notification.permission
ปัจจุบันคืออะไรเพื่อให้แน่ใจว่าไม่ใช่"denied"
สิทธิ์ที่ถูกปฏิเสธหมายความว่าคุณจะแสดงการแจ้งเตือนไม่ได้จนกว่าผู้ใช้จะเปลี่ยนสิทธิ์ในเบราว์เซอร์ด้วยตนเอง - หากต้องการตรวจสอบว่าระบบรองรับการรับส่งข้อความ Push หรือไม่ เราจะตรวจสอบว่า
PushManager
พร้อมใช้งานในออบเจ็กต์หน้าต่างหรือไม่ - สุดท้าย เราใช้
pushManager.getSubscription()
เพื่อตรวจสอบว่าเรามีการสมัครใช้บริการแล้วหรือยัง หากมี เราจะส่งรายละเอียดการสมัครใช้บริการไปยังเซิร์ฟเวอร์เพื่อให้มั่นใจว่าเรามีข้อมูลที่ถูกต้องและตั้งค่า UI เพื่อระบุว่าเปิดใช้การรับส่งข้อความ Push ไว้แล้วหรือยัง เราจะดูรายละเอียดที่มีอยู่ในออบเจ็กต์การสมัครใช้บริการในบทความนี้ในภายหลัง
เราจะรอจนกว่า navigator.serviceWorker.ready
จะได้รับการแก้ไขเพื่อตรวจสอบการสมัครใช้บริการและเปิดใช้ปุ่ม Push เนื่องจากคุณจะสมัครรับข้อความ Push ได้ก็ต่อเมื่อผู้ให้บริการทำงานอยู่
ขั้นตอนถัดไปคือจัดการเมื่อผู้ใช้ต้องการเปิดใช้ข้อความ Push แต่ก่อนอื่นเราต้องตั้งค่าโปรเจ็กต์ Google Developer Console และเพิ่มพารามิเตอร์บางอย่างลงในไฟล์ Manifest เพื่อใช้ Firebase Cloud Messaging (FCM) หรือเดิมเรียกว่า Google Cloud Messaging (GCM)
สร้างโปรเจ็กต์ในคอนโซลนักพัฒนาซอฟต์แวร์ Firebase
Chrome ใช้ FCM เพื่อจัดการการส่งและการนำส่งข้อความ Push แต่หากต้องการใช้ FCM API คุณต้องตั้งค่าโปรเจ็กต์ในคอนโซลนักพัฒนาแอป Firebase
ขั้นตอนต่อไปนี้มีไว้สำหรับ Chrome, Opera สําหรับ Android และ Samsung Browser ที่ใช้ FCM โดยเฉพาะ เราจะพูดถึงวิธีการทำงานของฟีเจอร์นี้ในเบราว์เซอร์อื่นๆ ในบทความนี้
สร้างโปรเจ็กต์นักพัฒนาแอป Firebase ใหม่
ในการเริ่มต้นใช้งาน คุณต้องสร้างโปรเจ็กต์ใหม่ใน https://console.firebase.google.com/ โดยคลิก "สร้างโปรเจ็กต์ใหม่"
เพิ่มชื่อโปรเจ็กต์ สร้างโปรเจ็กต์ แล้วระบบจะนําคุณไปยังแดชบอร์ดของโปรเจ็กต์
จากแดชบอร์ดนี้ ให้คลิกไอคอนรูปเฟืองข้างชื่อโปรเจ็กต์ที่มุมซ้ายบน แล้วคลิก "การตั้งค่าโปรเจ็กต์"
ในหน้าการตั้งค่า ให้คลิกแท็บ "การรับส่งข้อความบนระบบคลาวด์"
หน้านี้มีคีย์ API สําหรับการรับส่งข้อความ Push ซึ่งเราจะใช้ในภายหลัง และรหัสผู้ส่งที่เราต้องใส่ไว้ในไฟล์ Manifest ของเว็บแอปในส่วนถัดไป
เพิ่มไฟล์ Manifest ของเว็บแอป
สําหรับ Push เราจําเป็นต้องเพิ่มไฟล์ Manifest ที่มีช่อง gcm_sender_id เพื่อให้การสมัครรับ Push สําเร็จ พารามิเตอร์นี้จําเป็นสําหรับ Chrome, Opera สําหรับ Android และเบราว์เซอร์ Samsung เท่านั้นเพื่อให้ใช้ FCM / GCM ได้
เบราว์เซอร์เหล่านี้ใช้ gcm_sender_id เมื่อสมัครใช้บริการอุปกรณ์ของผู้ใช้กับ FCM ซึ่งหมายความว่า FCM จะระบุอุปกรณ์ของผู้ใช้และตรวจสอบว่ารหัสผู้ส่งตรงกับคีย์ API ที่เกี่ยวข้อง และผู้ใช้ได้อนุญาตให้เซิร์ฟเวอร์ส่งข้อความ Push ไปยังผู้ใช้แล้ว
ด้านล่างนี้คือไฟล์ Manifest ที่ง่ายมาก
{
"name": "Push Demo",
"short_name": "Push Demo",
"icons": [{
"src": "images/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}],
"start_url": "/index.html?homescreen=1",
"display": "standalone",
"gcm_sender_id": "<Your Sender ID Here>"
}
คุณจะต้องตั้งค่า gcm_sender_id เป็นรหัสผู้ส่งจากโปรเจ็กต์ Firebase
เมื่อบันทึกไฟล์ Manifest ในโปรเจ็กต์แล้ว (ใช้ชื่อ manifest.json ก็ได้) ให้อ้างอิงไฟล์จาก HTML ด้วยแท็กต่อไปนี้ในส่วนหัวของหน้า
<link rel="manifest" href="/manifest.json">
หากไม่เพิ่มไฟล์ Manifest ของเว็บที่มีพารามิเตอร์เหล่านี้ คุณจะได้รับข้อยกเว้นเมื่อพยายามสมัครใช้บริการ Push ของผู้ใช้พร้อมข้อผิดพลาด "Registration failed - no sender id provided"
หรือ "Registration failed -
permission denied"
สมัครรับการรับส่งข้อความ Push
เมื่อตั้งค่าไฟล์ Manifest แล้ว คุณสามารถกลับไปที่ JavaScript ของเว็บไซต์ได้
หากต้องการสมัครใช้บริการ คุณต้องเรียกใช้เมธอด subscribe() ในออบเจ็กต์ PushManager ซึ่งเข้าถึงได้ผ่าน ServiceWorkerRegistration
ซึ่งจะขอให้ผู้ใช้ให้สิทธิ์แก่ต้นทางในการส่งข้อความ Push หากไม่มีสิทธิ์นี้ คุณจะสมัครใช้บริการไม่สำเร็จ
หากสัญญาที่แสดงผลโดยเมธอด subscribe() สำเร็จ คุณจะได้รับออบเจ็กต์ PushSubscription ซึ่งมีปลายทาง
คุณควรบันทึกอุปกรณ์ปลายทางไว้ในเซิร์ฟเวอร์สำหรับผู้ใช้แต่ละราย เนื่องจากคุณจะต้องส่งข้อความ Push ในภายหลัง
โค้ดต่อไปนี้จะสมัครใช้บริการการรับข้อความ Push ให้กับผู้ใช้
function subscribe() {
// Disable the button so it can't be changed while
// we process the permission request
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = true;
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function(subscription) {
// The subscription was successful
isPushEnabled = true;
pushButton.textContent = 'Disable Push Messages';
pushButton.disabled = false;
// TODO: Send the subscription.endpoint to your server
// and save it to send a push message at a later date
return sendSubscriptionToServer(subscription);
})
.catch(function(e) {
if (Notification.permission === 'denied') {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
console.warn('Permission for Notifications was denied');
pushButton.disabled = true;
} else {
// A problem occurred with the subscription; common reasons
// include network errors, and lacking gcm_sender_id and/or
// gcm_user_visible_only in the manifest.
console.error('Unable to subscribe to push.', e);
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
}
});
});
}
ตอนนี้เว็บแอปของคุณพร้อมรับข้อความ Push แล้ว แต่จะไม่เกิดอะไรขึ้นจนกว่าเราจะเพิ่มโปรแกรมรับเหตุการณ์ Push ลงในไฟล์ Service Worker
Listener เหตุการณ์ Push ของ Service Worker
เมื่อได้รับข้อความ Push (เราจะพูดถึงวิธีส่งข้อความ Push จริงในส่วนถัดไป) ระบบจะส่งเหตุการณ์ Push ใน Service Worker ซึ่งคุณจะต้องแสดงการแจ้งเตือน
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';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
});
โค้ดนี้จะลงทะเบียน Listener เหตุการณ์ Push และแสดงการแจ้งเตือนที่มีชื่อ ข้อความเนื้อหา ไอคอน และแท็กการแจ้งเตือนที่กําหนดไว้ล่วงหน้า
สิ่งที่ควรสังเกตอย่างหนึ่งในตัวอย่างนี้คือevent.waitUntil()
method เมธอดนี้จะรับพรอมต์และขยายอายุของตัวแฮนเดิลเหตุการณ์ (หรืออาจกล่าวได้ว่าเป็นการทำให้ Service Worker ทำงานต่อไป) จนกว่าพรอมต์จะยุติ
ในกรณีนี้ พรอมต์ที่ส่งไปยัง event.waitUntil
คือพรอมต์ที่ได้จาก showNotification()
แท็กการแจ้งเตือนจะทำหน้าที่เป็นตัวระบุสำหรับการแจ้งเตือนที่ไม่ซ้ำกัน หากเราส่งข้อความ Push 2 รายการไปยังปลายทางเดียวกัน โดยมีการหน่วงเวลาสั้นๆ ระหว่างข้อความ และแสดงการแจ้งเตือนด้วยแท็กเดียวกัน เบราว์เซอร์จะแสดงการแจ้งเตือนแรกและแทนที่ด้วยการแจ้งเตือนที่ 2 เมื่อได้รับข้อความ Push
หากต้องการแสดงการแจ้งเตือนหลายรายการพร้อมกัน ให้ใช้แท็กอื่นหรือไม่มีแท็กเลย เราจะดูตัวอย่างที่สมบูรณ์มากขึ้นของการแสดงการแจ้งเตือนในภายหลังในโพสต์นี้ ในระหว่างนี้ เรามาลองทำแบบง่ายๆ และดูว่าการส่งข้อความ Push จะแสดงการแจ้งเตือนนี้ไหม
การส่งข้อความ Push
เราได้สมัครรับข้อความ Push และ Service Worker พร้อมแสดงการแจ้งเตือนแล้ว ตอนนี้ก็ถึงเวลาส่งข้อความ Push ผ่าน FCM
ซึ่งใช้ได้กับเบราว์เซอร์ที่ใช้ FCM เท่านั้น
เมื่อคุณส่งตัวแปร PushSubscription.endpoint
ไปยังเซิร์ฟเวอร์ จุดสิ้นสุดสําหรับ FCM จะมีลักษณะพิเศษ มีพารามิเตอร์ที่ส่วนท้ายของ URL ซึ่งเป็น registration_id
ตัวอย่างปลายทาง ได้แก่
https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP
URL ของ FCM คือ
https://fcm.googleapis.com/fcm/send
registration_id
จะเป็นดังนี้
APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP
ปัญหานี้เกิดขึ้นเฉพาะกับเบราว์เซอร์ที่ใช้ FCM ในเบราว์เซอร์ปกติ คุณเพียงแค่รับปลายทางและเรียกใช้ปลายทางนั้นด้วยวิธีมาตรฐาน แล้วปลายทางก็จะทํางานได้ไม่ว่าจะใช้ URL ใดก็ตาม
ซึ่งหมายความว่าคุณจะต้องตรวจสอบในเซิร์ฟเวอร์ว่าปลายทางเป็น FCM หรือไม่ หากใช่ ให้ดึงข้อมูล registration_id หากต้องการดำเนินการนี้ใน Python คุณอาจทำดังนี้
if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
endpointParts = endpoint.split('/')
registrationId = endpointParts[len(endpointParts) - 1]
endpoint = 'https://fcm.googleapis.com/fcm/send'
เมื่อได้รหัสการลงทะเบียนแล้ว คุณจะเรียกใช้ FCM API ได้ คุณดูเอกสารอ้างอิงเกี่ยวกับ FCM API ได้ที่นี่
สิ่งสำคัญที่ควรทราบเมื่อเรียกใช้ FCM มีดังนี้
- คุณต้องตั้งค่าส่วนหัวการให้สิทธิ์ซึ่งมีค่าเป็น
key=<YOUR_API_KEY>
เมื่อเรียกใช้ API โดยที่<YOUR_API_KEY>
คือคีย์ API จากโปรเจ็กต์ Firebase- FCM จะใช้คีย์ API เพื่อค้นหารหัสผู้ส่งที่เหมาะสม ตรวจสอบว่าผู้ใช้ให้สิทธิ์สำหรับโปรเจ็กต์ของคุณ และสุดท้ายตรวจสอบว่าที่อยู่ IP ของเซิร์ฟเวอร์อยู่ในรายการที่อนุญาตสำหรับโปรเจ็กต์นั้น
- ส่วนหัว
Content-Type
ที่เหมาะสมของapplication/json
หรือapplication/x-www-form-urlencoded;charset=UTF-8
โดยขึ้นอยู่กับว่าคุณส่งข้อมูลเป็น JSON หรือข้อมูลแบบฟอร์ม - อาร์เรย์
registration_ids
- รหัสการลงทะเบียนที่ดึงมาจากปลายทางของผู้ใช้
โปรดอ่านเอกสารประกอบเกี่ยวกับวิธีส่งข้อความ Push จากเซิร์ฟเวอร์ แต่หากต้องการตรวจสอบ Service Worker อย่างรวดเร็ว คุณสามารถใช้ cURL เพื่อส่งข้อความ Push ไปยังเบราว์เซอร์ได้
แทนที่ <YOUR_API_KEY>
และ <YOUR_REGISTRATION_ID>
ในคำสั่ง cURL นี้ด้วยข้อมูลของคุณเอง แล้วเรียกใช้จากเทอร์มินัล
คุณควรเห็นการแจ้งเตือนที่ยอดเยี่ยมนี้
curl --header "Authorization: key=<YOUR_API_KEY>" --header
"Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
"{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
เมื่อพัฒนาตรรกะแบ็กเอนด์ โปรดทราบว่าส่วนหัวการให้สิทธิ์และรูปแบบของเนื้อหา POST นั้นเจาะจงสำหรับปลายทาง FCM ดังนั้นให้ตรวจหาเมื่อปลายทางสำหรับ FCM แล้วเพิ่มส่วนหัวและจัดรูปแบบเนื้อหา POST ตามเงื่อนไข สําหรับเบราว์เซอร์อื่นๆ (และหวังว่า Chrome ในอนาคต) คุณจะต้องติดตั้งใช้งานโปรโตคอล Web Push
ข้อเสียของการใช้งาน Push API ใน Chrome ในปัจจุบันคือคุณจะส่งข้อมูลใดๆ กับข้อความ Push ไม่ได้ ไม่มี เหตุผลคือในการใช้งานในอนาคต ข้อมูลเพย์โหลดจะต้องได้รับการเข้ารหัสบนเซิร์ฟเวอร์ก่อนที่จะส่งไปยังปลายทางการรับส่งข้อความ Push วิธีนี้จะช่วยให้ปลายทาง ซึ่งเป็นผู้ให้บริการ Push ใดก็ตาม ไม่สามารถดูเนื้อหาของข้อความ Push ได้โดยง่าย นอกจากนี้ ยังช่วยป้องกันช่องโหว่อื่นๆ เช่น การตรวจสอบใบรับรอง HTTPS ที่ไม่ถูกต้องและการโจมตีแบบแทรกกลางการสื่อสารระหว่างเซิร์ฟเวอร์กับผู้ให้บริการ Push อย่างไรก็ตาม เรายังไม่รองรับการเข้ารหัสนี้ ดังนั้นในระหว่างนี้ คุณจะต้องดึงข้อมูลเพื่อรับข้อมูลที่จําเป็นในการสร้างการแจ้งเตือน
ตัวอย่างเหตุการณ์ Push ที่สมบูรณ์ยิ่งขึ้น
การแจ้งเตือนที่เราเห็นจนถึงตอนนี้ค่อนข้างพื้นฐานและตัวอย่างก็ไม่ค่อยครอบคลุม Use Case ในชีวิตจริง
ในทางปฏิบัติแล้ว ผู้ใช้ส่วนใหญ่ต้องการรับข้อมูลบางอย่างจากเซิร์ฟเวอร์ก่อนแสดงการแจ้งเตือน ซึ่งอาจเป็นข้อมูลที่จะป้อนข้อมูลในชื่อและข้อความการแจ้งเตือนด้วยข้อมูลบางอย่าง หรืออาจทำอย่างละเอียดยิ่งขึ้นด้วยการแคชหน้าเว็บหรือข้อมูลบางส่วนเพื่อให้ทุกอย่างพร้อมใช้งานทันทีเมื่อผู้ใช้คลิกการแจ้งเตือนเมื่อเปิดเบราว์เซอร์ แม้ว่าเครือข่ายจะไม่พร้อมใช้งานในขณะนั้นก็ตาม
ในโค้ดต่อไปนี้ เราจะดึงข้อมูลบางอย่างจาก API, แปลงการตอบกลับเป็นออบเจ็กต์ และใช้เพื่อแสดงข้อมูลการแจ้งเตือน
self.addEventListener('push', function(event) {
// Since there is no payload data with the first version
// of push messages, we'll grab some data from
// an API and use it to populate a notification
event.waitUntil(
fetch(SOME_API_ENDPOINT).then(function(response) {
if (response.status !== 200) {
// Either show a message to the user explaining the error
// or enter a generic message and handle the
// onnotificationclick event to direct the user to a web page
console.log('Looks like there was a problem. Status Code: ' + response.status);
throw new Error();
}
// Examine the text in the response
return response.json().then(function(data) {
if (data.error || !data.notification) {
console.error('The API returned an error.', data.error);
throw new Error();
}
var title = data.notification.title;
var message = data.notification.message;
var icon = data.notification.icon;
var notificationTag = data.notification.tag;
return self.registration.showNotification(title, {
body: message,
icon: icon,
tag: notificationTag
});
});
}).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';
var icon = URL_TO_DEFAULT_ICON;
var notificationTag = 'notification-error';
return self.registration.showNotification(title, {
body: message,
icon: icon,
tag: notificationTag
});
})
);
});
เราขอเน้นย้ำอีกครั้งว่า event.waitUntil()
ใช้ Promise ซึ่งส่งผลให้ showNotification()
แสดงผล Promise ซึ่งหมายความว่า Listener เหตุการณ์จะไม่ออกจนกว่าการเรียกใช้ fetch()
แบบแอซิงโครนัสจะเสร็จสมบูรณ์และระบบจะแสดงการแจ้งเตือน
คุณจะเห็นว่าเราแสดงการแจ้งเตือนแม้ว่าจะมีข้อผิดพลาดก็ตาม เนื่องจากหากไม่ทำเช่นนั้น Chrome จะแสดงการแจ้งเตือนทั่วไปของตนเอง
การเปิด URL เมื่อผู้ใช้คลิกการแจ้งเตือน
เมื่อผู้ใช้คลิกการแจ้งเตือน ระบบจะส่งเหตุการณ์ notificationclick
ใน Service Worker คุณดำเนินการที่เหมาะสมภายในตัวแฮนเดิลได้ เช่น โฟกัสแท็บหรือเปิดหน้าต่างที่มี URL ที่เฉพาะเจาะจง ดังนี้
self.addEventListener('notificationclick', function(event) {
console.log('On notification click: ', event.notification.tag);
// Android doesn't close the notification when you click on it
// See: http://crbug.com/463146
event.notification.close();
// This looks to see if the current is already open and
// focuses if it is
event.waitUntil(
clients.matchAll({
type: "window"
})
.then(function(clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
if (client.url == '/' && 'focus' in client)
return client.focus();
}
if (clients.openWindow) {
return clients.openWindow('/');
}
})
);
});
ตัวอย่างนี้จะเปิดเบราว์เซอร์ไปยังรูทของต้นทางของเว็บไซต์ โดยโฟกัสที่แท็บต้นทางเดียวกันที่มีอยู่ หากมี หรือเปิดแท็บใหม่
โปรดดูโพสต์ที่อธิบายสิ่งที่คุณทำได้ด้วย Notification API ที่นี่
ยกเลิกการสมัครรับอีเมลในอุปกรณ์ของผู้ใช้
คุณได้สมัครใช้บริการอุปกรณ์ของผู้ใช้และผู้ใช้ได้รับข้อความ Push แล้ว แต่คุณจะยกเลิกการสมัครใช้บริการได้อย่างไร
สิ่งที่ต้องทำหลักๆ เพื่อยกเลิกการสมัครใช้บริการในอุปกรณ์ของผู้ใช้คือการเรียกใช้เมธอด unsubscribe()
ในออบเจ็กต์ PushSubscription และนำปลายทางออกจากเซิร์ฟเวอร์ (เพื่อไม่ให้ส่งข้อความ Push ที่รู้ว่าผู้ใช้จะไม่รับ) โค้ดด้านล่างทําสิ่งต่อไปนี้
function unsubscribe() {
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = true;
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
// To unsubscribe from push messaging, you need get the
// subscription object, which you can call unsubscribe() on.
serviceWorkerRegistration.pushManager.getSubscription().then(
function(pushSubscription) {
// Check we have a subscription to unsubscribe
if (!pushSubscription) {
// No subscription object, so set the state
// to allow the user to subscribe to push
isPushEnabled = false;
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
return;
}
var subscriptionId = pushSubscription.subscriptionId;
// TODO: Make a request to your server to remove
// the subscriptionId from your data store so you
// don't attempt to send them push messages anymore
// We have a subscription, so call unsubscribe on it
pushSubscription.unsubscribe().then(function(successful) {
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
isPushEnabled = false;
}).catch(function(e) {
// We failed to unsubscribe, this can lead to
// an unusual state, so may be best to remove
// the users data from your data store and
// inform the user that you have done so
console.log('Unsubscription error: ', e);
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
});
}).catch(function(e) {
console.error('Error thrown while unsubscribing from push messaging.', e);
});
});
}
การอัปเดตการสมัครใช้บริการให้เป็นปัจจุบัน
การสมัครใช้บริการอาจไม่ซิงค์กันระหว่าง FCM กับเซิร์ฟเวอร์ ตรวจสอบว่าเซิร์ฟเวอร์ของคุณแยกวิเคราะห์เนื้อหาการตอบกลับของการส่ง POST ของ FCM API โดยมองหาผลลัพธ์ error:NotRegistered
และ canonical_id
ตามที่อธิบายไว้ในเอกสารประกอบของ FCM
การสมัครใช้บริการอาจไม่ซิงค์กันระหว่าง Service Worker กับเซิร์ฟเวอร์ด้วย ตัวอย่างเช่น หลังจากสมัคร/ยกเลิกการสมัครใช้บริการเรียบร้อยแล้ว การเชื่อมต่อเครือข่ายที่ไม่เสถียรอาจทำให้คุณอัปเดตเซิร์ฟเวอร์ไม่ได้ หรือผู้ใช้อาจเพิกถอนสิทธิ์การแจ้งเตือน ซึ่งจะทริกเกอร์การยกเลิกการสมัครใช้บริการโดยอัตโนมัติ จัดการกรณีดังกล่าวโดยตรวจสอบผลลัพธ์ของ serviceWorkerRegistration.pushManager.getSubscription()
เป็นระยะๆ (เช่น เมื่อโหลดหน้าเว็บ) และซิงค์กับเซิร์ฟเวอร์ นอกจากนี้ คุณอาจต้องขอให้ระบบสมัครใช้บริการอีกครั้งโดยอัตโนมัติหากไม่มีการสมัครใช้บริการแล้ว และ Notification.permission == "granted"
ใน sendSubscriptionToServer()
คุณจะต้องพิจารณาวิธีจัดการกับคำขอเครือข่ายที่ไม่สำเร็จเมื่ออัปเดต endpoint
โซลูชันหนึ่งคือติดตามสถานะของ endpoint
ในคุกกี้เพื่อพิจารณาว่าเซิร์ฟเวอร์ของคุณต้องใช้รายละเอียดล่าสุดหรือไม่
ขั้นตอนทั้งหมดข้างต้นจะส่งผลให้มีการใช้การรับส่งข้อความ Push บนเว็บใน Chrome 46 อย่างเต็มรูปแบบ ยังมีฟีเจอร์ตามข้อกำหนดที่จะช่วยให้คุณทำงานได้ง่ายขึ้น (เช่น API มาตรฐานสำหรับการเรียกให้แสดงข้อความ Push) แต่รุ่นนี้จะช่วยให้คุณเริ่มสร้างการรับส่งข้อความ Push ลงในเว็บแอปได้ตั้งแต่วันนี้
วิธีแก้ไขข้อบกพร่องของเว็บแอป
ในระหว่างการใช้ข้อความ Push ข้อบกพร่องจะอยู่ในที่ใดที่หนึ่งใน 2 ที่ ได้แก่ หน้าเว็บหรือ Service Worker
คุณแก้ไขข้อบกพร่องในหน้าเว็บได้โดยใช้ DevTools หากต้องการแก้ไขข้อบกพร่องเกี่ยวกับ Service Worker คุณมี 2 ตัวเลือก ดังนี้
- ไปที่ chrome://inspect > Service workers มุมมองนี้ไม่ได้ให้ข้อมูลมากนัก นอกเหนือจาก Service Worker ที่ทำงานอยู่ในปัจจุบัน
- ไปที่ chrome://serviceworker-internals จากที่นี่ คุณสามารถดูสถานะของ Service Worker และดูข้อผิดพลาด (หากมี) หน้านี้มีไว้ชั่วคราวจนกว่าเครื่องมือสำหรับนักพัฒนาเว็บจะมีชุดฟีเจอร์ที่คล้ายกัน
เคล็ดลับที่ดีที่สุดอย่างหนึ่งที่เรามอบให้แก่ผู้ที่เพิ่งเริ่มใช้ Service Worker คือให้ใช้ช่องทําเครื่องหมายชื่อ "เปิดหน้าต่างเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์และหยุดการเรียกใช้ JavaScript ชั่วคราวเมื่อ Service Worker เริ่มทํางานเพื่อแก้ไขข้อบกพร่อง" ช่องทําเครื่องหมายนี้จะเพิ่มจุดหยุดพักที่จุดเริ่มต้นของ Service Worker และหยุดการดําเนินการชั่วคราว ซึ่งจะช่วยให้คุณดําเนินการต่อหรือดูสคริปต์ Service Worker ทีละขั้นตอนเพื่อดูว่าพบปัญหาหรือไม่
หากดูเหมือนว่ามีปัญหาระหว่าง FCM กับเหตุการณ์ Push ของ Service Worker คุณจะไม่สามารถแก้ไขข้อบกพร่องได้ เนื่องจากไม่มีวิธีให้คุณดูว่า Chrome ได้รับข้อมูลใดๆ หรือไม่ สิ่งที่ต้องตรวจสอบคือคําตอบจาก FCM สำเร็จเมื่อเซิร์ฟเวอร์เรียก API โดยจะมีหน้าตาดังตัวอย่างต่อไปนี้
{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}
สังเกตคําตอบ "success": 1
หากเห็นข้อความ "ไม่สําเร็จ" แทน แสดงว่ารหัสการลงทะเบียน FCM ไม่ถูกต้องและระบบไม่ได้ส่งข้อความ Push ไปยัง Chrome
การแก้ไขข้อบกพร่อง Service Worker ใน Chrome สําหรับ Android
ขณะนี้การแก้ไขข้อบกพร่อง Service Worker ใน Chrome สำหรับ Android ยังไม่ชัดเจน คุณต้องไปที่ chrome://inspect ค้นหาอุปกรณ์ แล้วมองหารายการในรายการที่มีชื่อ "Worker pid:...." ซึ่งมี URL ของ Service Worker
UX สําหรับข้อความ Push
ทีม Chrome กำลังรวบรวมเอกสารแนวทางปฏิบัติแนะนำสำหรับ UX ของข้อความ Push รวมถึงเอกสารที่ครอบคลุมกรณีการใช้งานที่พบไม่บ่อยเมื่อทำงานกับข้อความ Push
อนาคตของการรับส่งข้อความ Push ใน Chrome และเว็บแบบเปิด
ส่วนนี้จะอธิบายรายละเอียดเล็กน้อยเกี่ยวกับส่วนต่างๆ ของ Chrome ที่เกี่ยวข้องกับการติดตั้งใช้งานนี้ที่คุณควรทราบ และความแตกต่างกับการติดตั้งใช้งานเบราว์เซอร์อื่นๆ
โปรโตคอลและปลายทางของ Web Push
ข้อดีของมาตรฐาน Push API คือคุณควรใช้ Endpoint ส่งไปยังเซิร์ฟเวอร์ และส่งข้อความ Push โดยใช้ Web Push Protocol ได้
Web Push Protocol เป็นมาตรฐานใหม่ที่ผู้ให้บริการ Push สามารถใช้ได้ ซึ่งช่วยให้นักพัฒนาแอปไม่ต้องกังวลว่าผู้ให้บริการ Push จะเป็นใคร แนวคิดคือวิธีนี้ช่วยให้ไม่ต้องลงชื่อสมัครใช้คีย์ API และส่งข้อมูลที่จัดรูปแบบเป็นพิเศษ เช่น ที่คุณต้องทำกับ FCM
Chrome เป็นเบราว์เซอร์แรกที่นำ Push API มาใช้ และ FCM ไม่รองรับ Web Push Protocol ซึ่งเป็นเหตุผลที่ Chrome ต้องใช้ gcm_sender_id
และคุณต้องใช้ Restful API สำหรับ FCM
เป้าหมายสุดท้ายของ Chrome คือการเปลี่ยนไปใช้ Web Push Protocol กับ Chrome และ FCM
ในระหว่างนี้ คุณต้องตรวจหาปลายทาง "https://fcm.googleapis.com/fcm/send" และจัดการแยกจากปลายทางอื่นๆ เช่น จัดรูปแบบข้อมูลเพย์โหลดในลักษณะที่เฉพาะเจาะจงและเพิ่มคีย์การให้สิทธิ์
วิธีใช้โปรโตคอล Web Push
ปัจจุบัน Firefox Nightly กำลังพัฒนา Push และอาจกลายเป็นเบราว์เซอร์แรกที่ใช้งาน Web Push Protocol
คำถามที่พบบ่อย
ข้อมูลจำเพาะอยู่ที่ไหน
https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/
ฉันจะป้องกันการแจ้งเตือนที่ซ้ำกันได้อย่างไรหากการแสดงข้อมูลบนเว็บมีต้นทางหลายแห่ง หรือหากฉันมีทั้งการแสดงข้อมูลบนเว็บและการแสดงข้อมูลทั่วไป
ยังไม่มีวิธีแก้ปัญหานี้ในขณะนี้ แต่คุณสามารถติดตามความคืบหน้าใน Chromium
สถานการณ์ในอุดมคติคือต้องมีรหัสประเภทใดประเภทหนึ่งสําหรับอุปกรณ์ของผู้ใช้ จากนั้นฝั่งเซิร์ฟเวอร์จะจับคู่รหัสการสมัครใช้บริการของแอปเนทีฟและเว็บแอป แล้วตัดสินใจว่าจะส่งข้อความ Push ไปยังแอปใด คุณอาจทำเช่นนี้ผ่านขนาดหน้าจอ รูปแบบอุปกรณ์ การแชร์คีย์ที่สร้างขึ้นระหว่างเว็บแอปกับแอปเนทีฟ แต่ทั้ง 2 วิธีนี้มีทั้งข้อดีและข้อเสีย
เหตุใดฉันจึงต้องใช้ gcm_sender_id
ซึ่งจำเป็นต้องใช้เพื่อให้ Chrome, Opera สำหรับ Android และเบราว์เซอร์ Samsung ใช้ Firebase Cloud Messaging (FCM) API ได้ เป้าหมายคือการใช้ Web Push Protocol เมื่อมาตรฐานได้รับการสรุปแล้วและ FCM รองรับ
เหตุผลที่ไม่ควรใช้ Web Sockets หรือ เหตุการณ์ที่ส่งจากเซิร์ฟเวอร์ (EventSource)
ข้อดีของการใช้ข้อความ Push คือแม้ว่าหน้าเว็บจะปิดอยู่ แต่ Service Worker ก็จะตื่นขึ้นและแสดงการแจ้งเตือนได้ Web Sockets และ EventSource จะปิดการเชื่อมต่อเมื่อหน้าเว็บหรือเบราว์เซอร์ปิด
จะเกิดอะไรขึ้นหากฉันไม่ต้องการการนำส่งเหตุการณ์ในเบื้องหลัง
หากคุณไม่จําเป็นต้องแสดงโฆษณาในเบื้องหลัง Web Sockets เป็นตัวเลือกที่ยอดเยี่ยม
ฉันจะใช้ Push โดยไม่แสดงการแจ้งเตือนได้เมื่อใด (เช่น Push แบบไม่มีเสียงในเบื้องหลัง)
ยังไม่มีลำดับเวลาว่าฟีเจอร์นี้จะพร้อมใช้งานเมื่อใด แต่เรามีความตั้งใจที่จะใช้การซิงค์เบื้องหลัง และแม้ว่าจะยังไม่ได้ตัดสินใจหรือระบุข้อกำหนด แต่ก็มีบางประเด็นที่พูดถึงการเปิดใช้ Push แบบเงียบด้วยการซิงค์เบื้องหลัง
เหตุใดจึงต้องใช้ HTTPS ฉันจะแก้ปัญหานี้ในระหว่างการพัฒนาได้อย่างไร
Service Worker ต้องใช้ต้นทางที่ปลอดภัยเพื่อให้แน่ใจว่าสคริปต์ Service Worker มาจากต้นทางที่ต้องการและไม่ได้มาจากการคุกคามแบบคนกลาง ปัจจุบัน หมายความว่าต้องใช้ HTTPS ในเว็บไซต์ที่เผยแพร่ แม้ว่า localhost จะใช้งานได้ในระหว่างการพัฒนาก็ตาม
การรองรับเบราว์เซอร์มีลักษณะอย่างไร
Chrome รองรับในเวอร์ชันเสถียรและ Mozilla กำลังพัฒนาฟีเจอร์นี้ใน Firefox Nightly ดูข้อมูลเพิ่มเติมได้จากข้อบกพร่องเกี่ยวกับการติดตั้งใช้งาน Push API และติดตามการติดตั้งใช้งานการแจ้งเตือนได้ที่นี่
ฉันจะนำการแจ้งเตือนออกหลังจากผ่านไปแล้วระยะเวลาหนึ่งได้ไหม
ขณะนี้ยังดำเนินการไม่ได้ แต่เรากำลังวางแผนที่จะเพิ่มการรองรับเพื่อดูรายการการแจ้งเตือนที่มองเห็นได้ในขณะนี้ หากคุณมี Use Case ในการกําหนดเวลาหมดอายุของการแจ้งเตือนหลังจากที่แสดงการแจ้งเตือนว่าสร้างแล้ว เราอยากทราบ Use Case นั้น โปรดเพิ่มความคิดเห็นและเราจะส่งต่อให้ทีม Chrome
หากต้องการหยุดส่งข้อความ Push ไปยังผู้ใช้หลังจากผ่านไประยะเวลาหนึ่งเท่านั้น และไม่สนใจว่าผู้ใช้จะเห็นการแจ้งเตือนนานเท่าใด คุณก็ใช้พารามิเตอร์ "Time To Live" (TTL) ของ FCM ได้ ดูข้อมูลเพิ่มเติมที่นี่
การรับส่งข้อความ Push ใน Chrome มีข้อจำกัดอะไรบ้าง
ข้อจำกัดบางประการที่ระบุไว้ในโพสต์นี้
- การใช้ CCM ของ Chrome เป็นบริการ Push จะทำให้เกิดข้อกำหนดที่เป็นกรรมสิทธิ์จำนวนหนึ่ง เรากำลังดำเนินการร่วมกันเพื่อดูว่าจะยกเลิกข้อจำกัดบางรายการเหล่านี้ได้หรือไม่ในอนาคต
- คุณต้องแสดงการแจ้งเตือนเมื่อได้รับข้อความ Push
- Chrome ในเดสก์ท็อปมีข้อจำกัดคือหาก Chrome ไม่ทำงาน คุณจะไม่ได้รับข้อความ Push ซึ่งแตกต่างจาก ChromeOS และ Android ที่ผู้ใช้จะได้รับข้อความ Push เสมอ
เราไม่ควรใช้ Permissions API ใช่ไหม
Permission API มีการใช้งานใน Chrome แต่อาจไม่พร้อมใช้งานในเบราว์เซอร์บางรุ่น ดูข้อมูลเพิ่มเติมได้ที่นี่
เหตุใด Chrome จึงไม่เปิดแท็บก่อนหน้าเมื่อฉันคลิกการแจ้งเตือน
ปัญหานี้มีผลกับหน้าเว็บที่ Service Worker ไม่ได้ควบคุมอยู่ในขณะนี้เท่านั้น ดูข้อมูลเพิ่มเติมได้ที่นี่
จะเกิดอะไรขึ้นหากการแจ้งเตือนล้าสมัยเมื่ออุปกรณ์ของผู้ใช้ได้รับการพุช
คุณต้องแสดงการแจ้งเตือนทุกครั้งที่ได้รับข้อความ Push ในกรณีที่คุณต้องการส่งการแจ้งเตือนแต่การแจ้งเตือนนั้นมีประโยชน์เพียงระยะเวลาหนึ่ง คุณสามารถใช้พารามิเตอร์ "time_to_live" ใน CCM เพื่อให้ FCM ไม่ได้ส่งข้อความ Push หากพ้นเวลาหมดอายุ
ดูรายละเอียดเพิ่มเติมได้ที่นี่
จะเกิดอะไรขึ้นหากฉันส่งข้อความ Push 10 ข้อความแต่ต้องการให้อุปกรณ์ได้รับเพียงข้อความเดียว
FCM มีพารามิเตอร์ "collapse_key" ที่คุณสามารถใช้เพื่อบอก FCM ให้แทนที่ข้อความที่รอดำเนินการซึ่งมี "collapse_key" เดียวกันด้วยข้อความใหม่