Pola notifikasi umum

Kita akan melihat beberapa pola implementasi umum untuk web push.

Hal ini melibatkan penggunaan beberapa API berbeda yang tersedia di pekerja layanan.

Peristiwa tutup 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 pengguna mengklik silang atau menggeser notifikasi, bukan mengklik 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 data yang ada 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 berikut:

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 clients.openWindow() API.

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 kita melihat cara mencapainya, perlu menyoroti bahwa hal ini hanya dapat dilakukan untuk halaman di origin Anda. Ini karena kita hanya bisa melihat halaman terbuka milik situs kita. Hal ini mencegah developer melihat semua situs yang dilihat pengguna.

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 rapi 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 menjadikan URL itu absolut sehingga kita bisa mencocokkannya dengan URL jendela nanti.

const urlToOpen = new URL(examplePage, self.location.origin).href;

Kemudian, kita akan mendapatkan daftar objek WindowClient, yang merupakan daftar tab dan jendela yang saat ini dibuka. (Ingat ini hanya tab 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 "jendela" (yaitu cukup mencari tab dan jendela dan mengecualikan pekerja web). includeUncontrolled memungkinkan kita menelusuri semua tab dari origin yang tidak dikontrol oleh pekerja layanan saat ini, yaitu pekerja layanan yang menjalankan kode ini. Biasanya, Anda selalu ingin includeUncontrolled bernilai benar saat memanggil matchAll().

Kita mengambil promise yang ditampilkan sebagai promiseChain sehingga dapat meneruskannya ke event.waitUntil() nanti, sehingga pekerja layanan tetap aktif.

Saat promise matchAll() di-iterasi, kami akan melakukan iterasi melalui klien jendela yang ditampilkan dan membandingkan URL-nya dengan URL yang ingin dibuka. Jika menemukan kecocokan, kami memfokuskan klien itu, yang akan menarik perhatian pengguna. Fokus dilakukan dengan panggilan matchingClient.focus().

Jika tidak dapat menemukan klien yang cocok, kami 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

Kita melihat bahwa menambahkan tag ke notifikasi berarti ikut serta dalam perilaku di mana notifikasi yang ada dengan tag yang sama akan diganti.

Namun, Anda dapat menjadi lebih canggih dengan menciutkan notifikasi menggunakan Notifications API. Pertimbangkan aplikasi chat, tempat developer mungkin ingin notifikasi baru menampilkan pesan yang mirip dengan "You have two messages from 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, anggaplah setiap notifikasi memiliki beberapa data yang mencakup nama pengguna.

Hal pertama yang perlu kita lakukan adalah menemukan notifikasi terbuka untuk pengguna yang memiliki nama pengguna tertentu. Kita akan mendapatkan registration.getNotifications() dan mengulanginya 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 berikutnya adalah mengganti notifikasi ini dengan notifikasi baru.

Dalam aplikasi pesan palsu ini, kita akan melacak jumlah pesan baru dengan menambahkan hitungan 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, kami menambah jumlah pesan dan menetapkan judul notifikasi serta isi pesan sebagaimana mestinya. Jika tidak ada notifikasi, kami 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 ini:

Notifikasi kedua dengan penggabungan.

Keuntungan dari pendekatan ini adalah jika pengguna Anda menyaksikan notifikasi muncul satu sama lain, maka akan terlihat dan terasa lebih kohesif daripada hanya mengganti notifikasi dengan pesan terbaru.

Pengecualian terhadap aturan

Kami telah menyatakan bahwa Anda harus menampilkan notifikasi saat menerima push dan ini benar biasanya. Satu-satunya skenario saat Anda tidak perlu menampilkan notifikasi adalah saat pengguna membuka situs dan fokus.

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 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 mengulanginya dengan 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 tidak perlu menampilkan pemberitahuan jika pengguna sedang berada di situs Anda. Namun, bagaimana jika Anda masih ingin memberi tahu pengguna bahwa suatu 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 pembaruan kepada pengguna, yang memberi tahu mereka tentang peristiwa tersebut. Hal ini berguna untuk situasi saat notifikasi halus di halaman lebih baik dan lebih ramah bagi pengguna.

Katakanlah kita telah menerima push, memeriksa bahwa aplikasi web saat ini fokus, kemudian 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, kami memproses pesan dengan menambahkan pemroses peristiwa pesan:

navigator.serviceWorker.addEventListener('message', function (event) {
  console.log('Received a message from service worker: ', event.data);
});

Dalam pemroses pesan ini, Anda dapat melakukan apa pun yang diinginkan, menampilkan UI kustom di halaman, atau mengabaikan pesan sepenuhnya.

Perlu diperhatikan juga bahwa jika Anda tidak menentukan pemroses pesan di halaman web Anda, pesan dari pekerja layanan tidak akan melakukan apa pun.

Meng-cache halaman dan membuka jendela

Salah satu skenario yang berada di luar cakupan panduan ini, tetapi perlu dibahas adalah bahwa Anda dapat meningkatkan UX aplikasi web secara keseluruhan dengan meng-cache halaman web yang Anda harapkan akan dikunjungi pengguna setelah mengklik notifikasi.

Hal ini memerlukan penyiapan pekerja layanan untuk menangani peristiwa fetch. Namun, jika Anda menerapkan pemroses peristiwa fetch, pastikan untuk memanfaatkannya dalam peristiwa push dengan meng-cache halaman dan aset yang diperlukan sebelum menampilkan notifikasi.

Kompatibilitas browser

Peristiwa notificationclose

Dukungan Browser

  • 50
  • 17
  • 44
  • 16

Sumber

Clients.openWindow()

Dukungan Browser

  • 40
  • 17
  • 44
  • 11.1

Sumber

ServiceWorkerRegistration.getNotifications()

Dukungan Browser

  • 40
  • 17
  • 44
  • 16

Sumber

clients.matchAll()

Dukungan Browser

  • 42
  • 17
  • 54
  • 11.1

Sumber

Untuk informasi selengkapnya, lihat pengantar postingan pekerja layanan ini.

Langkah berikutnya

Lab kode