Langkah pertama adalah mendapatkan izin dari pengguna untuk mengirimkan pesan push kepada mereka, lalu kita bisa mendapatkan PushSubscription
.
JavaScript API untuk melakukan hal ini cukup mudah, jadi mari kita telusuri alur logika.
Deteksi fitur
Pertama-tama kita perlu memeriksa apakah {i>browser <i} saat ini mendukung {i>push messaging<i}. Kita dapat memeriksa apakah push didukung dengan dua pemeriksaan sederhana.
- Periksa serviceWorker di navigator.
- Periksa PushManager di window.
if (!('serviceWorker' in navigator)) {
// Service Worker isn't supported on this browser, disable or hide UI.
return;
}
if (!('PushManager' in window)) {
// Push isn't supported on this browser, disable or hide UI.
return;
}
Meskipun dukungan browser berkembang dengan cepat untuk pekerja layanan dan pesan push, sebaiknya Anda memiliki deteksi fitur untuk keduanya dan meningkatkan kualitas secara progresif.
Mendaftarkan pekerja layanan
Dengan deteksi fitur, kita tahu bahwa pekerja layanan dan Push didukung. Langkah berikutnya adalah "mendaftarkan" pekerja layanan kita.
Ketika mendaftarkan pekerja layanan, kita memberi tahu browser lokasi file pekerja layanan. File tersebut masih berupa JavaScript, tetapi browser akan "memberikan akses" ke API pekerja layanan, termasuk push. Lebih tepatnya, browser menjalankan file di lingkungan pekerja layanan.
Untuk mendaftarkan pekerja layanan, panggil navigator.serviceWorker.register()
, dengan meneruskan jalur ke file kita. Seperti ini:
function registerServiceWorker() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
console.log('Service worker successfully registered.');
return registration;
})
.catch(function (err) {
console.error('Unable to register service worker.', err);
});
}
Fungsi ini memberi tahu browser bahwa kita memiliki file service worker dan lokasinya. Dalam
hal ini, file pekerja layanan berada di /service-worker.js
. Di balik layar, browser akan melakukan langkah berikut setelah memanggil register()
:
Download file pekerja layanan.
Jalankan JavaScript.
Jika semuanya berjalan dengan benar dan tidak ada error, promise yang ditampilkan oleh
register()
akan diselesaikan. Jika ada kesalahan dalam bentuk apa pun, promise akan ditolak.
Jika
register()
menolak, periksa kembali JavaScript Anda untuk menemukan kesalahan ketik / error di Chrome DevTools.
Setelah di-resolve, register()
akan menampilkan ServiceWorkerRegistration
. Kita akan menggunakan pendaftaran ini untuk mengakses PushManager API.
Kompatibilitas browser API PushManager
Meminta izin
Kita telah mendaftarkan pekerja layanan dan siap membuat pengguna berlangganan, langkah berikutnya adalah mendapatkan izin dari pengguna untuk mengirimkan pesan push.
API untuk mendapatkan izin relatif sederhana. Kelemahannya adalah API tersebut baru-baru ini diubah dari menerima callback menjadi menampilkan Promise. Masalah ini adalah kita tidak dapat mengetahui versi API mana yang diimplementasikan oleh browser saat ini, sehingga Anda harus mengimplementasikan keduanya dan menangani keduanya.
function askPermission() {
return new Promise(function (resolve, reject) {
const 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.");
}
});
}
Dalam kode di atas, cuplikan kode yang penting adalah panggilan ke
Notification.requestPermission()
. Metode ini akan menampilkan perintah kepada pengguna:
Setelah pengguna berinteraksi dengan dialog izin dengan menekan Izinkan, Blokir, atau cukup menutupnya,
kita akan diberi hasilnya sebagai string: 'granted'
, 'default'
, atau 'denied'
.
Dalam kode contoh di atas, promise yang ditampilkan oleh askPermission()
akan di-resolve jika izin diberikan. Jika tidak, kita akan menampilkan error yang membuat promise ditolak.
Satu kasus ekstrem yang perlu Anda tangani adalah jika pengguna mengklik tombol 'Blokir'. Jika hal ini terjadi, aplikasi web Anda tidak akan dapat meminta izin lagi kepada pengguna. Mereka harus "membuka blokir" aplikasi secara manual dengan mengubah status izinnya, yang tersembunyi di panel setelan. Pikirkan baik-baik cara dan waktu Anda meminta izin kepada pengguna, karena jika mereka mengklik blokir, bukan cara mudah untuk membatalkan keputusan tersebut.
Kabar baiknya, sebagian besar pengguna dengan senang hati memberikan izin selama mereka mengetahui alasan permintaan izin tersebut.
Kita akan melihat bagaimana beberapa situs populer meminta izin nanti.
Membuat pengguna berlangganan dengan PushManager
Setelah pekerja layanan terdaftar dan mendapatkan izin, kita bisa membuat pengguna berlangganan dengan
memanggil registration.pushManager.subscribe()
.
function subscribeUserToPush() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
),
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function (pushSubscription) {
console.log(
'Received PushSubscription: ',
JSON.stringify(pushSubscription),
);
return pushSubscription;
});
}
Saat memanggil metode subscribe()
, kita meneruskan objek options, yang terdiri dari
parameter wajib dan opsional.
Mari kita lihat semua opsi yang bisa kita teruskan.
Opsi userVisibleOnly
Ketika push pertama kali ditambahkan ke browser, ada ketidakpastian tentang apakah developer harus dapat mengirim pesan push dan tidak menampilkan notifikasi. Hal ini biasanya disebut sebagai push senyap, karena pengguna tidak mengetahui bahwa sesuatu telah terjadi di latar belakang.
Masalahnya adalah developer dapat melakukan hal-hal buruk seperti melacak lokasi pengguna secara terus-menerus tanpa diketahui pengguna.
Untuk menghindari skenario ini dan memberikan waktu kepada penulis spesifikasi untuk mempertimbangkan cara terbaik dalam mendukung fitur ini, opsi userVisibleOnly
ditambahkan dan meneruskan nilai true
adalah perjanjian simbolis dengan browser bahwa aplikasi web akan menampilkan notifikasi setiap kali push diterima (yaitu tidak ada push diam).
Saat ini, Anda harus memasukkan nilai true
. Jika Anda tidak menyertakan kunci userVisibleOnly
atau meneruskan false
, Anda akan mendapatkan error berikut:
Chrome saat ini hanya mendukung Push API untuk langganan yang akan menghasilkan pesan yang terlihat oleh pengguna. Anda dapat menunjukkannya dengan memanggil pushManager.subscribe({userVisibleOnly: true})
. Lihat https://goo.gl/yqv4Q4 untuk mengetahui detail selengkapnya.
Sepertinya push senyap menyeluruh tidak akan pernah diterapkan di Chrome. Sebaliknya, penulis spesifikasi mempelajari gagasan API anggaran yang akan memungkinkan aplikasi web menerima sejumlah pesan push senyap tertentu berdasarkan penggunaan aplikasi web.
Opsi applicationServerKey
Kami menyebutkan secara singkat "kunci server aplikasi" di bagian sebelumnya. "Kunci server aplikasi" digunakan oleh layanan push untuk mengidentifikasi aplikasi yang membuat pengguna berlangganan dan memastikan bahwa aplikasi yang sama mengirimkan pesan kepada pengguna tersebut.
Kunci server aplikasi adalah pasangan kunci publik dan pribadi yang unik untuk aplikasi Anda. Kunci pribadi harus dirahasiakan untuk aplikasi Anda, dan kunci publik dapat dibagikan dengan bebas.
Opsi applicationServerKey
yang diteruskan ke panggilan subscribe()
adalah kunci publik
aplikasi. Browser meneruskannya ke layanan push saat pengguna berlangganan, yang berarti layanan push dapat mengaitkan kunci publik aplikasi Anda ke PushSubscription
pengguna.
Diagram di bawah menggambarkan langkah-langkah ini.
- Aplikasi web Anda dimuat di browser, lalu memanggil
subscribe()
, yang meneruskan kunci server aplikasi publik Anda. - Selanjutnya, browser membuat permintaan jaringan ke layanan push yang akan membuat endpoint, mengaitkan endpoint ini dengan kunci publik aplikasi, dan menampilkan endpoint ke browser.
- Browser akan menambahkan endpoint ini ke
PushSubscription
, yang ditampilkan melalui promisesubscribe()
.
Jika nantinya Anda ingin mengirim pesan push, Anda harus membuat header Authorization yang akan berisi informasi yang ditandatangani dengan kunci pribadi server aplikasi Anda. Saat menerima permintaan untuk mengirim pesan push, layanan push dapat memvalidasi header Otorisasi yang ditandatangani ini dengan mencari kunci publik yang ditautkan ke endpoint yang menerima permintaan tersebut. Jika tanda tangan tersebut valid, layanan push tahu bahwa tanda tangan itu harus berasal dari server aplikasi dengan kunci pribadi yang cocok. Pada dasarnya, ini adalah langkah keamanan yang mencegah orang lain mengirim pesan ke pengguna aplikasi.
Secara teknis, applicationServerKey
bersifat opsional. Namun, penerapan paling mudah
di Chrome memerlukannya, dan browser lain mungkin memerlukannya di
masa mendatang. Ini opsional di Firefox.
Spesifikasi yang menentukan apa kunci server aplikasi yang seharusnya adalah spesifikasi VAPID. Setiap kali Anda membaca sesuatu yang mengacu pada "kunci server aplikasi" atau "kunci VAPID", ingatlah bahwa keduanya sama.
Cara membuat kunci server aplikasi
Anda dapat membuat kumpulan kunci server aplikasi publik dan pribadi dengan membuka web-push-codelab.glitch.me atau Anda dapat menggunakan command line web-push untuk membuat kunci dengan melakukan hal berikut:
$ npm install -g web-push
$ web-push generate-vapid-keys
Anda hanya perlu membuat kunci ini satu kali untuk aplikasi Anda, tetapi pastikan Anda menjaga kerahasiaan kunci pribadi. (Ya, saya baru saja mengatakan itu.)
Izin dan subscribe()
Ada satu efek samping memanggil subscribe()
. Jika aplikasi web Anda tidak memiliki izin untuk menampilkan notifikasi pada saat memanggil subscribe()
, browser akan meminta izin untuk Anda. Hal ini berguna jika UI Anda berfungsi dengan alur ini, tetapi jika Anda menginginkan lebih banyak
kontrol (dan saya rasa sebagian besar developer akan memerlukannya), tetap gunakan Notification.requestPermission()
API
yang kita gunakan sebelumnya.
Apa itu PushSubscription?
Kita memanggil subscribe()
, meneruskan beberapa opsi, dan sebagai gantinya kita mendapatkan promise yang di-resolve menjadi PushSubscription
sehingga menghasilkan beberapa kode seperti ini:
function subscribeUserToPush() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
),
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function (pushSubscription) {
console.log(
'Received PushSubscription: ',
JSON.stringify(pushSubscription),
);
return pushSubscription;
});
}
Objek PushSubscription
berisi semua informasi yang diperlukan untuk mengirim pesan push kepada pengguna tersebut. Jika Anda mencetak konten menggunakan JSON.stringify()
, Anda akan melihat
hal berikut:
{
"endpoint": "https://some.pushservice.com/something-unique",
"keys": {
"p256dh":
"BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
"auth":"FPssNDTKnInHVndSTdbKFw=="
}
}
endpoint
adalah URL layanan push. Untuk memicu pesan push, buat permintaan POST
ke URL ini.
Objek keys
berisi nilai yang digunakan untuk mengenkripsi data pesan yang dikirim dengan pesan push
(yang akan kita bahas nanti di bagian ini).
Berlangganan lagi secara rutin untuk mencegah habisnya masa berlaku
Saat berlangganan notifikasi push, Anda sering menerima PushSubscription.expirationTime
dari null
. Secara teori, hal ini berarti langganan tidak akan pernah berakhir (berbeda dengan saat Anda menerima DOMHighResTimeStamp
, yang memberi tahu kapan tepatnya langganan berakhir). Namun, dalam praktiknya, umumnya browser masih membiarkan masa berlaku langganan berakhir, misalnya, jika tidak ada notifikasi push yang diterima untuk waktu yang lebih lama, atau jika browser mendeteksi bahwa pengguna tidak menggunakan aplikasi yang memiliki izin notifikasi push. Salah satu pola untuk mencegah hal ini adalah dengan membuat pengguna berlangganan lagi setiap kali notifikasi diterima, seperti ditunjukkan dalam cuplikan berikut. Hal ini mengharuskan Anda untuk cukup sering mengirim notifikasi agar browser tidak menghentikan langganan secara otomatis, dan Anda harus mempertimbangkan dengan sangat hati-hati kelebihan dan kekurangan kebutuhan notifikasi yang sah terhadap spam tanpa disengaja kepada pengguna agar masa berlaku langganan tidak berakhir. Pada akhirnya, Anda tidak boleh mencoba melawan browser dalam upayanya untuk melindungi pengguna dari langganan notifikasi yang sudah lama terlupakan.
/* In the Service Worker. */
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
// Display notification or handle data
// Example: show a notification
const title = 'New Notification';
const body = 'You have new updates!';
const icon = '/images/icon.png';
const tag = 'simple-push-demo-notification-tag';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
// Attempt to resubscribe after receiving a notification
event.waitUntil(resubscribeToPush());
});
function resubscribeToPush() {
return self.registration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.then(function() {
return self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
});
})
.then(function(subscription) {
console.log('Resubscribed to push notifications:', subscription);
// Optionally, send new subscription details to your server
})
.catch(function(error) {
console.error('Failed to resubscribe:', error);
});
}
Mengirim langganan ke Server Anda
Setelah Anda memiliki langganan push, Anda dapat mengirimkannya ke server Anda. Anda dapat menentukan cara untuk
melakukannya, tetapi sebaiknya gunakan JSON.stringify()
untuk mendapatkan semua data yang diperlukan dari
objek langganan. Atau, Anda dapat mengumpulkan hasil yang sama
secara manual seperti ini:
const subscriptionObject = {
endpoint: pushSubscription.endpoint,
keys: {
p256dh: pushSubscription.getKeys('p256dh'),
auth: pushSubscription.getKeys('auth'),
},
};
// The above is the same output as:
const subscriptionObjectToo = JSON.stringify(pushSubscription);
Pengiriman langganan dilakukan di halaman web seperti berikut:
function sendSubscriptionToBackEnd(subscription) {
return fetch('/api/save-subscription/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(subscription),
})
.then(function (response) {
if (!response.ok) {
throw new Error('Bad status code from server.');
}
return response.json();
})
.then(function (responseData) {
if (!(responseData.data && responseData.data.success)) {
throw new Error('Bad response from server.');
}
});
}
Server node menerima permintaan ini dan menyimpan data ke database untuk digunakan nanti.
app.post('/api/save-subscription/', function (req, res) {
if (!isValidSaveRequest(req, res)) {
return;
}
return saveSubscriptionToDatabase(req.body)
.then(function (subscriptionId) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({data: {success: true}}));
})
.catch(function (err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(
JSON.stringify({
error: {
id: 'unable-to-save-subscription',
message:
'The subscription was received but we were unable to save it to our database.',
},
}),
);
});
});
Dengan detail PushSubscription
di server, kita dapat mengirim pesan
kepada pengguna kapan pun kita mau.
Berlangganan lagi secara rutin untuk mencegah habisnya masa berlaku
Saat berlangganan notifikasi push, Anda sering menerima PushSubscription.expirationTime
dari null
. Secara teori, hal ini berarti langganan tidak akan pernah berakhir (berbeda dengan saat Anda menerima DOMHighResTimeStamp
, yang memberi tahu kapan tepatnya langganan berakhir). Namun, dalam praktiknya, umumnya browser masih membiarkan masa berlaku langganan berakhir, misalnya, jika tidak ada notifikasi push yang diterima untuk waktu yang lama, atau jika browser mendeteksi bahwa pengguna tidak menggunakan aplikasi yang memiliki izin notifikasi push. Salah satu pola untuk mencegah hal ini adalah dengan membuat pengguna berlangganan lagi setiap kali notifikasi diterima, seperti ditunjukkan dalam cuplikan berikut. Ini mengharuskan Anda mengirim notifikasi cukup sering agar browser tidak memiliki langganan yang telah habis masa berlakunya secara otomatis, dan Anda harus mempertimbangkan dengan sangat hati-hati kelebihan dan kekurangan kebutuhan notifikasi yang sah terhadap spam kepada pengguna agar masa berlaku langganan tidak berakhir. Pada akhirnya, Anda tidak boleh mencoba melawan browser dalam upayanya untuk melindungi pengguna dari langganan notifikasi yang sudah lama terlupakan.
/* In the Service Worker. */
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
// Display notification or handle data
// Example: show a notification
const title = 'New Notification';
const body = 'You have new updates!';
const icon = '/images/icon.png';
const tag = 'simple-push-demo-notification-tag';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
// Attempt to resubscribe after receiving a notification
event.waitUntil(resubscribeToPush());
});
function resubscribeToPush() {
return self.registration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.then(function() {
return self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
});
})
.then(function(subscription) {
console.log('Resubscribed to push notifications:', subscription);
// Optionally, send new subscription details to your server
})
.catch(function(error) {
console.error('Failed to resubscribe:', error);
});
}
FAQ
Beberapa pertanyaan umum yang diajukan orang saat ini:
Dapatkah saya mengubah layanan push yang digunakan browser?
Tidak. Layanan push dipilih oleh browser dan seperti yang kita lihat pada
panggilan subscribe()
, browser akan membuat permintaan jaringan ke layanan push
untuk mengambil detail yang membentuk PushSubscription.
Setiap browser menggunakan Push Service yang berbeda, bukankah mereka memiliki API yang berbeda?
Semua layanan push akan mengharapkan API yang sama.
API umum ini disebut Web Push Protocol dan menjelaskan permintaan jaringan yang perlu dibuat oleh aplikasi Anda untuk memicu pesan push.
Jika saya berlangganan pengguna melalui desktop, apakah mereka juga berlangganan di ponsel?
Sayangnya tidak. Pengguna harus mendaftar push pada setiap browser tempat mereka ingin menerima pesan. Perlu diketahui juga bahwa hal ini akan mengharuskan pengguna memberikan izin di setiap perangkat.
Langkah berikutnya
- Ringkasan Notifikasi Push Web
- Cara Kerja Push
- Membuat Langganan Pengguna
- UX Izin
- Mengirim Pesan dengan Library Web Push
- Protokol Push Web
- Menangani Peristiwa Push
- Menampilkan Notifikasi
- Perilaku Notifikasi
- Pola Notifikasi Umum
- FAQ Notifikasi Push
- Masalah Umum dan Melaporkan Bug