Kita akan melihat beberapa pola penerapan umum untuk web push.
Ini melibatkan penggunaan beberapa API berbeda yang tersedia di pekerja layanan.
Peristiwa penutupan notifikasi
Di bagian terakhir, kita telah melihat cara memproses peristiwa notificationclick
.
Ada juga peristiwa notificationclose
yang dipanggil jika pengguna menutup salah satu notifikasi
Anda (yaitu, bukan mengklik notifikasi, pengguna mengklik tanda silang atau menggeser
notifikasi).
Peristiwa ini biasanya digunakan untuk analisis guna melacak interaksi pengguna dengan notifikasi.
self.addEventListener('notificationclose', function (event) {
const dismissedNotification = event.notification;
const promiseChain = notificationCloseAnalytics();
event.waitUntil(promiseChain);
});
Menambahkan data ke notifikasi
Saat pesan push diterima, biasanya ada data yang hanya berguna jika pengguna telah mengklik notifikasi. Misalnya, URL yang harus dibuka saat notifikasi diklik.
Cara termudah untuk mengambil data dari peristiwa push dan melampirkannya ke notifikasi adalah dengan menambahkan parameter data
ke objek opsi yang diteruskan ke showNotification()
, seperti ini:
const options = {
body:
'This notification has data attached to it that is printed ' +
"to the console when it's clicked.",
tag: 'data-notification',
data: {
time: new Date(Date.now()).toString(),
message: 'Hello, World!',
},
};
registration.showNotification('Notification with Data', options);
Di dalam pengendali klik, data dapat diakses dengan event.notification.data
.
const notificationData = event.notification.data;
console.log('');
console.log('The notification data has the following parameters:');
Object.keys(notificationData).forEach((key) => {
console.log(` ${key}: ${notificationData[key]}`);
});
console.log('');
Membuka jendela
Salah satu respons paling umum terhadap notifikasi adalah membuka
jendela/tab ke URL tertentu. Kita dapat melakukannya dengan API clients.openWindow()
.
Dalam peristiwa notificationclick
, kita akan menjalankan beberapa kode seperti ini:
const examplePage = '/demos/notification-examples/example-page.html';
const promiseChain = clients.openWindow(examplePage);
event.waitUntil(promiseChain);
Di bagian berikutnya, kita akan melihat cara memeriksa apakah halaman yang ingin kita arahkan kepada pengguna sudah terbuka atau belum. Dengan cara ini, kita dapat memfokuskan tab yang terbuka, bukan membuka tab baru.
Memfokuskan jendela yang ada
Jika memungkinkan, kita harus memfokuskan jendela, bukan membuka jendela baru setiap kali pengguna mengklik notifikasi.
Sebelum kami melihat cara mencapainya, perlu diperhatikan bahwa hal ini hanya dapat dilakukan untuk halaman di origin Anda. Hal ini karena kita hanya dapat melihat halaman yang terbuka yang merupakan bagian dari situs kita. Hal ini mencegah developer tidak dapat melihat semua situs yang dilihat pengguna mereka.
Dengan mengambil contoh sebelumnya, kita akan mengubah kode untuk melihat apakah
/demos/notification-examples/example-page.html
sudah terbuka.
const urlToOpen = new URL(examplePage, self.location.origin).href;
const promiseChain = clients
.matchAll({
type: 'window',
includeUncontrolled: true,
})
.then((windowClients) => {
let matchingClient = null;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.url === urlToOpen) {
matchingClient = windowClient;
break;
}
}
if (matchingClient) {
return matchingClient.focus();
} else {
return clients.openWindow(urlToOpen);
}
});
event.waitUntil(promiseChain);
Mari kita pelajari kode tersebut.
Pertama, kita mengurai halaman contoh menggunakan URL API. Ini adalah trik keren yang saya pelajari dari Jeff Posnick. Memanggil new URL()
dengan objek location
akan menampilkan URL absolut jika string yang diteruskan bersifat relatif (yaitu /
akan menjadi https://example.com/
).
Kita membuat URL menjadi absolut sehingga kita dapat mencocokkannya dengan URL jendela nanti.
const urlToOpen = new URL(examplePage, self.location.origin).href;
Kemudian, kita mendapatkan daftar objek WindowClient
, yang merupakan daftar tab dan jendela yang saat ini terbuka. (Ingat, tab ini hanya untuk origin Anda.)
const promiseChain = clients.matchAll({
type: 'window',
includeUncontrolled: true,
});
Opsi yang diteruskan ke matchAll
akan memberi tahu browser bahwa kita hanya ingin menelusuri klien jenis "window" (yaitu cukup mencari tab dan jendela, serta mengecualikan pekerja web). includeUncontrolled
memungkinkan kita menelusuri
semua tab dari origin Anda yang tidak dikontrol oleh pekerja layanan
saat ini, yaitu pekerja layanan yang menjalankan kode ini. Secara umum, Anda
akan selalu ingin includeUncontrolled
bernilai benar saat memanggil matchAll()
.
Kita mengambil promise yang ditampilkan sebagai promiseChain
sehingga kita dapat meneruskannya ke
event.waitUntil()
nanti, sehingga service worker tetap aktif.
Saat promise matchAll()
di-resolve, kita akan melakukan iterasi melalui klien jendela yang ditampilkan dan membandingkan URL-nya dengan URL yang ingin kita buka. Jika kami menemukan kecocokan, kami memfokuskan
klien tersebut, yang akan membawa jendela tersebut ke perhatian pengguna. Pemfokusan selesai dengan
panggilan matchingClient.focus()
.
Jika tidak dapat menemukan klien yang cocok, kita akan membuka jendela baru, sama seperti di bagian sebelumnya.
.then((windowClients) => {
let matchingClient = null;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.url === urlToOpen) {
matchingClient = windowClient;
break;
}
}
if (matchingClient) {
return matchingClient.focus();
} else {
return clients.openWindow(urlToOpen);
}
});
Menggabungkan notifikasi
Kami melihat bahwa menambahkan tag ke notifikasi akan memilih perilaku saat notifikasi yang ada dengan tag yang sama akan diganti.
Namun, Anda dapat melakukan tindakan yang lebih canggih dengan menciutkan notifikasi menggunakan Notifications API. Pertimbangkan aplikasi chat, tempat developer mungkin ingin notifikasi baru menampilkan pesan yang mirip dengan "Anda memiliki dua pesan dari Matt", bukan hanya menampilkan pesan terbaru.
Anda dapat melakukannya, atau memanipulasi notifikasi saat ini dengan cara lain, menggunakan API registration.getNotifications() yang memberi Anda akses ke semua notifikasi yang saat ini terlihat untuk aplikasi web Anda.
Mari kita lihat bagaimana kita dapat menggunakan API ini untuk menerapkan contoh chat.
Di aplikasi chat, misalkan setiap notifikasi memiliki beberapa data yang mencakup nama pengguna.
Hal pertama yang ingin kita lakukan adalah menemukan notifikasi terbuka untuk pengguna dengan nama pengguna
tertentu. Kita akan mendapatkan registration.getNotifications()
dan melakukan loop di atasnya serta memeriksa
notification.data
untuk nama pengguna tertentu:
const promiseChain = registration.getNotifications().then((notifications) => {
let currentNotification;
for (let i = 0; i < notifications.length; i++) {
if (notifications[i].data && notifications[i].data.userName === userName) {
currentNotification = notifications[i];
}
}
return currentNotification;
});
Langkah selanjutnya adalah mengganti notifikasi ini dengan notifikasi baru.
Di aplikasi pesan palsu ini, kita akan melacak jumlah pesan baru dengan menambahkan jumlah ke data notifikasi baru dan menambahkannya dengan setiap notifikasi baru.
.then((currentNotification) => {
let notificationTitle;
const options = {
icon: userIcon,
}
if (currentNotification) {
// We have an open notification, let's do something with it.
const messageCount = currentNotification.data.newMessageCount + 1;
options.body = `You have ${messageCount} new messages from ${userName}.`;
options.data = {
userName: userName,
newMessageCount: messageCount
};
notificationTitle = `New Messages from ${userName}`;
// Remember to close the old notification.
currentNotification.close();
} else {
options.body = `"${userMessage}"`;
options.data = {
userName: userName,
newMessageCount: 1
};
notificationTitle = `New Message from ${userName}`;
}
return registration.showNotification(
notificationTitle,
options
);
});
Jika ada notifikasi yang saat ini ditampilkan, kita akan menambah jumlah pesan dan menetapkan judul serta pesan isi notifikasi. Jika tidak ada notifikasi, kita akan membuat notifikasi baru dengan newMessageCount
1.
Hasilnya adalah pesan pertama akan terlihat seperti ini:
Notifikasi kedua akan menciutkan notifikasi menjadi seperti ini:
Keuntungan pendekatan ini adalah jika pengguna melihat notifikasi muncul di atas yang lain, notifikasi akan terlihat dan terasa lebih kohesif daripada hanya mengganti notifikasi dengan pesan terbaru.
Pengecualian untuk aturan
Kami telah menyatakan bahwa Anda harus menampilkan notifikasi saat menerima push dan hal ini umumnya benar. Satu skenario saat Anda tidak perlu menampilkan notifikasi adalah saat pengguna membuka dan memfokuskan situs Anda.
Di dalam peristiwa push, Anda dapat memeriksa apakah Anda perlu menampilkan notifikasi atau tidak dengan memeriksa klien jendela dan mencari jendela yang difokuskan.
Kode untuk mendapatkan semua jendela dan mencari jendela yang difokuskan akan terlihat seperti ini:
function isClientFocused() {
return clients
.matchAll({
type: 'window',
includeUncontrolled: true,
})
.then((windowClients) => {
let clientIsFocused = false;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.focused) {
clientIsFocused = true;
break;
}
}
return clientIsFocused;
});
}
Kita menggunakan clients.matchAll()
untuk mendapatkan semua klien jendela, lalu melakukan loop untuk memeriksa parameter focused
.
Di dalam peristiwa push, kita akan menggunakan fungsi ini untuk memutuskan apakah perlu menampilkan notifikasi:
const promiseChain = isClientFocused().then((clientIsFocused) => {
if (clientIsFocused) {
console.log("Don't need to show a notification.");
return;
}
// Client isn't focused, we need to show a notification.
return self.registration.showNotification('Had to show a notification.');
});
event.waitUntil(promiseChain);
Mengirim pesan ke halaman dari peristiwa push
Kami telah melihat bahwa Anda dapat melewati tampilan notifikasi jika pengguna saat ini berada di situs Anda. Namun, bagaimana jika Anda tetap ingin memberi tahu pengguna bahwa suatu peristiwa telah terjadi, tetapi notifikasi terlalu berat?
Salah satu pendekatannya adalah dengan mengirim pesan dari pekerja layanan ke halaman. Dengan cara ini, halaman web dapat menampilkan notifikasi atau update kepada pengguna, yang memberi tahu mereka tentang peristiwa tersebut. Hal ini berguna untuk situasi saat notifikasi halus di halaman lebih baik dan lebih mudah bagi pengguna.
Misalnya, kita telah menerima push, memeriksa bahwa aplikasi web kita saat ini difokuskan, lalu kita dapat "memposting pesan" ke setiap halaman yang terbuka, seperti ini:
const promiseChain = isClientFocused().then((clientIsFocused) => {
if (clientIsFocused) {
windowClients.forEach((windowClient) => {
windowClient.postMessage({
message: 'Received a push message.',
time: new Date().toString(),
});
});
} else {
return self.registration.showNotification('No focused windows', {
body: 'Had to show a notification instead of messaging each page.',
});
}
});
event.waitUntil(promiseChain);
Di setiap halaman, kita memproses pesan dengan menambahkan pemroses peristiwa pesan:
navigator.serviceWorker.addEventListener('message', function (event) {
console.log('Received a message from service worker: ', event.data);
});
Di pemroses pesan ini, Anda dapat melakukan apa pun yang Anda inginkan, menampilkan UI kustom di halaman atau mengabaikan pesan sepenuhnya.
Perlu juga diperhatikan bahwa jika Anda tidak menentukan pemroses pesan di halaman web, pesan dari pekerja layanan tidak akan melakukan apa pun.
Menyimpan halaman ke dalam cache dan membuka jendela
Satu skenario yang berada di luar cakupan panduan ini, tetapi perlu dibahas adalah Anda dapat meningkatkan UX aplikasi web secara keseluruhan dengan meng-cache halaman web yang diharapkan akan dikunjungi pengguna setelah mengklik notifikasi Anda.
Hal ini memerlukan penyiapan pekerja layanan untuk menangani peristiwa fetch
,
tetapi jika Anda menerapkan pemroses peristiwa fetch
, pastikan Anda memanfaatkannya
dalam peristiwa push
dengan meng-cache halaman dan aset
yang diperlukan sebelum menampilkan notifikasi.
Kompatibilitas browser
Peristiwa notificationclose
Clients.openWindow()
ServiceWorkerRegistration.getNotifications()
clients.matchAll()
Untuk informasi selengkapnya, lihat postingan pengantar service worker ini.
Langkah berikutnya
- Ringkasan Notifikasi Push Web
- Cara Kerja Push
- Mendaftarkan Pengguna
- UX Izin
- Mengirim Pesan dengan Library Web Push
- Protokol Web Push
- Menangani Peristiwa Push
- Menampilkan Notifikasi
- Perilaku Notifikasi
- Pola Notifikasi Umum
- FAQ Notifikasi Push
- Masalah Umum dan Melaporkan Bug