Langkah pertama adalah mendapatkan izin dari pengguna untuk mengirim pesan push kepada mereka, lalu kita dapat
mendapatkan PushSubscription
.
JavaScript API untuk melakukan hal ini cukup mudah, jadi mari kita bahas alur logikanya.
Deteksi fitur
Pertama, kita perlu memeriksa apakah browser saat ini benar-benar mendukung pesan push. 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 fitur deteksi untuk keduanya dan ditingkatkan secara progresif.
Mendaftarkan pekerja layanan
Dengan deteksi fitur, kita tahu bahwa pekerja layanan dan Push didukung. Langkah berikutnya adalah "mendaftarkan" pekerja layanan.
Saat mendaftarkan service worker, kita memberi tahu browser tempat file service worker berada. File ini masih berupa JavaScript, tetapi browser akan "memberinya akses" ke API service worker, 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. Contoh:
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 pekerja layanan dan lokasinya. Dalam
hal ini, file pekerja layanan berada di /service-worker.js
. Di balik layar, browser
akan melakukan langkah-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 di-resolve. Jika ada error apa pun, promise akan ditolak.
Jika
register()
menolak, periksa kembali JavaScript Anda untuk menemukan kesalahan ketik/error di Chrome DevTools.
Saat register()
di-resolve, ServiceWorkerRegistration
akan ditampilkan. Kita akan menggunakan pendaftaran
ini untuk mengakses PushManager API.
Kompatibilitas browser PushManager API
Meminta izin
Kita telah mendaftarkan pekerja layanan dan siap untuk membuat pengguna berlangganan. Langkah berikutnya adalah mendapatkan izin dari pengguna untuk mengirim pesan push kepada mereka.
API untuk mendapatkan izin relatif sederhana. Kelemahannya adalah API baru-baru ini berubah dari mengambil callback menjadi menampilkan Promise. Masalahnya, kita tidak dapat mengetahui versi API yang diterapkan oleh browser saat ini, sehingga Anda harus menerapkan 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 hanya menutupnya,
kita akan diberi hasilnya sebagai string: 'granted'
, 'default'
, atau 'denied'
.
Dalam contoh kode 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 "membatalkan pemblokiran" aplikasi Anda secara manual dengan mengubah status izinnya, yang tersembunyi di panel setelan. Pikirkan dengan cermat cara dan waktu Anda meminta izin kepada pengguna, karena jika mereka mengklik blokir, tidak mudah untuk membatalkan keputusan tersebut.
Kabar baiknya adalah sebagian besar pengguna dapat memberikan izin selama mereka tahu alasan permintaan izin tersebut.
Kita akan melihat cara beberapa situs populer meminta izin nanti.
Membuat pengguna berlangganan dengan PushManager
Setelah mendaftarkan pekerja layanan dan mendapatkan izin, kita dapat 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 dapat kita teruskan.
Opsi userVisibleOnly
Saat 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.
Kekhawatirannya adalah developer dapat melakukan hal-hal buruk seperti melacak lokasi pengguna secara berkelanjutan tanpa sepengetahuan pengguna.
Untuk menghindari skenario ini dan memberikan waktu kepada penulis spesifikasi guna mempertimbangkan cara terbaik untuk mendukung fitur
ini, opsi userVisibleOnly
telah ditambahkan dan meneruskan nilai true
merupakan perjanjian
simbolik dengan browser bahwa aplikasi web akan menampilkan notifikasi setiap kali push
diterima (yaitu tanpa push diam).
Saat ini Anda harus meneruskan nilai true
. Jika 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.
Saat ini, fitur ini terlihat seperti push diam-diam yang tidak akan pernah diterapkan di Chrome. Sebagai gantinya, penulis spesifikasi sedang mempelajari konsep API anggaran yang akan memungkinkan aplikasi web mengirim sejumlah pesan push senyap berdasarkan penggunaan aplikasi web.
Opsi applicationServerKey
Kita telah menyebutkan "kunci server aplikasi" secara singkat di bagian sebelumnya. "Kunci server aplikasi" digunakan oleh layanan push untuk mengidentifikasi aplikasi yang berlangganan pengguna dan memastikan bahwa aplikasi yang sama mengirim 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 secara 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 dan Anda memanggil
subscribe()
, yang meneruskan kunci server aplikasi publik Anda. - Browser kemudian 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 nanti 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 mengirimkan pesan push, layanan push dapat memvalidasi header Authorization yang ditandatangani ini dengan mencari kunci publik yang ditautkan ke endpoint yang menerima permintaan tersebut. Jika tanda tangan valid, layanan push akan mengetahui bahwa tanda tangan tersebut harus berasal dari server aplikasi dengan kunci pribadi yang cocok. Ini pada dasarnya adalah langkah keamanan yang mencegah orang lain mengirim pesan kepada pengguna aplikasi.
Secara teknis, applicationServerKey
bersifat opsional. Namun, penerapan termudah
di Chrome memerlukannya, dan browser lain mungkin memerlukannya di
masa mendatang. Kolom ini bersifat opsional di Firefox.
Spesifikasi yang menentukan apa yang harus menjadi kunci server aplikasi adalah spesifikasi VAPID. Setiap kali Anda membaca sesuatu yang merujuk pada "kunci server aplikasi" atau "kunci VAPID", ingatlah bahwa keduanya adalah hal yang sama.
Cara membuat kunci server aplikasi
Anda dapat membuat kumpulan kunci server aplikasi publik dan pribadi dengan membuka web-push-codelab.glitch.me atau 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, tetapi pastikan Anda menjaga kerahasiaan kunci pribadinya. (Ya, saya baru saja mengatakan itu.)
Izin dan subscribe()
Ada satu efek samping dari 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 kontrol
yang lebih besar (dan saya rasa sebagian besar developer menginginkannya), tetap gunakan Notification.requestPermission()
API
yang kita gunakan sebelumnya.
Apa yang dimaksud dengan PushSubscription?
Kita memanggil subscribe()
, meneruskan beberapa opsi, dan sebagai hasilnya, kita mendapatkan promise yang me-resolve ke
PushSubscription
yang 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 ke pengguna tersebut. Jika 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).
Langganan ulang reguler untuk mencegah masa berlaku habis
Saat berlangganan notifikasi push, Anda sering menerima PushSubscription.expirationTime
dari null
. Secara teori, ini berarti langganan tidak pernah berakhir (berbeda dengan saat Anda menerima DOMHighResTimeStamp
, yang memberi tahu Anda waktu persis saat 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 kembali setelah setiap notifikasi diterima, seperti yang ditunjukkan dalam cuplikan berikut. Ini mengharuskan Anda untuk mengirim notifikasi cukup sering bagi browser agar tidak mengundurkan diri secara otomatis dari langganan, dan Anda harus mempertimbangkan dengan cermat kelebihan dan kekurangan notifikasi yang sah terhadap pengiriman spam kepada pengguna secara tidak sengaja hanya agar langganan tidak kedaluwarsa. Pada akhirnya, Anda tidak boleh mencoba melawan browser dalam upayanya 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 memiliki langganan push, Anda dapat mengirimkannya ke server. Anda dapat melakukannya dengan cara apa saja, tetapi ada tips kecil untuk menggunakan JSON.stringify()
guna mendapatkan semua data yang diperlukan dari objek langganan. Atau, Anda dapat menggabungkan 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 ini:
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
setiap kali kita mau.
Langganan ulang reguler untuk mencegah masa berlaku habis
Saat berlangganan notifikasi push, Anda sering menerima PushSubscription.expirationTime
dari null
. Secara teori, ini berarti langganan tidak pernah berakhir (berbeda dengan saat Anda menerima DOMHighResTimeStamp
, yang memberi tahu Anda waktu persis saat langganan berakhir). Namun, dalam praktiknya, browser biasanya tetap mengizinkan langganan berakhir, misalnya, jika tidak ada notifikasi push yang diterima dalam waktu 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 kembali setelah setiap notifikasi diterima, seperti yang ditunjukkan dalam cuplikan berikut. Hal ini mengharuskan Anda mengirim notifikasi cukup sering agar browser tidak otomatis menghentikan langganan, dan Anda harus mempertimbangkan dengan sangat cermat kelebihan dan kekurangan kebutuhan notifikasi yang sah dibandingkan dengan mengirim spam kepada pengguna hanya agar 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 pada tahap 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 Layanan Push 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 harus dilakukan aplikasi Anda untuk memicu pesan push.
Jika saya membuat pengguna berlangganan melalui desktop, apakah mereka juga berlangganan di ponsel?
Sayangnya, tidak. Pengguna harus mendaftar untuk push di setiap browser yang ingin digunakan untuk menerima pesan. Perlu juga diperhatikan bahwa hal ini akan mengharuskan pengguna memberikan izin di setiap perangkat.
Langkah berikutnya
- Ringkasan Notifikasi Push Web
- Cara Kerja Push
- Berlangganan Pengguna
- UX Izin
- Mengirim Pesan dengan Library Push Web
- Protokol Web Push
- Menangani Peristiwa Push
- Menampilkan Notifikasi
- Perilaku Notifikasi
- Pola Notifikasi Umum
- FAQ Notifikasi Push
- Masalah Umum dan Bug Pelaporan