Pola notifikasi umum

Kita akan melihat beberapa pola penerapan umum untuk web push.

Hal ini akan 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 demikian, 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 kita melihat cara melakukannya, sebaiknya perhatikan 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 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 bahwa ini adalah tab khusus untuk origin Anda.)

const promiseChain = clients.matchAll({
  type: 'window',
  includeUncontrolled: true,
});

Opsi yang diteruskan ke matchAll memberi tahu browser bahwa kita hanya ingin menelusuri klien jenis "window" (yaitu hanya mencari tab dan jendela dan 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() diselesaikan, kita akan melakukan iterasi melalui klien jendela yang ditampilkan dan membandingkan URL-nya dengan URL yang ingin kita buka. Jika menemukan kecocokan, kita akan memfokuskan klien tersebut, yang akan mengarahkan jendela tersebut ke perhatian pengguna. Pemfokusan dilakukan 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 cara menggunakan API ini untuk menerapkan contoh chat.

Di aplikasi chat, misalkan setiap notifikasi memiliki beberapa data yang menyertakan 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 pertama tanpa penggabungan.

Notifikasi kedua akan menciutkan notifikasi menjadi seperti ini:

Notifikasi kedua dengan penggabungan.

Kelebihan pendekatan ini adalah jika pengguna melihat notifikasi yang muncul satu per satu, 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 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 kita melakukan loop untuk memeriksa parameter focused.

Di dalam peristiwa push, kita akan menggunakan fungsi ini untuk memutuskan apakah kita 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 masih ingin memberi tahu pengguna bahwa peristiwa telah terjadi, tetapi notifikasi terlalu berat?

Salah satu pendekatannya adalah 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 Anda, 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

Dukungan Browser

  • Chrome: 50.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 16.

Sumber

Clients.openWindow()

Dukungan Browser

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1.

Sumber

ServiceWorkerRegistration.getNotifications()

Dukungan Browser

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 16.

Sumber

clients.matchAll()

Dukungan Browser

  • Chrome: 42.
  • Edge: 17.
  • Firefox: 54.
  • Safari: 11.1.

Sumber

Untuk mengetahui informasi selengkapnya, lihat postingan pengantar pekerja layanan ini.

Langkah berikutnya

Codelab