Pola notifikasi umum

Kita akan melihat beberapa pola implementasi umum untuk web push.

Ini melibatkan penggunaan beberapa API berbeda yang tersedia di pekerja layanan.

Peristiwa penutupan notifikasi

Di bagian terakhir, kita telah mempelajari cara memproses peristiwa notificationclick.

Ada juga peristiwa notificationclose yang dipanggil jika pengguna menutup salah satu notifikasi (yaitu, pengguna mengklik tanda silang atau menggeser notifikasi hilang).

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

Ketika pesan {i>push<i} diterima, biasanya data yang didapat hanya berguna jika pengguna telah mengklik notifikasi. Misalnya, URL yang harus dibuka saat notifikasi diklik.

Cara termudah untuk mengambil data dari kejadian push dan melampirkannya ke notifikasi adalah menambahkan parameter data ke objek opsi yang diteruskan ke dalam 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 dengan membuka jendela / tab ke URL tertentu. Kita bisa melakukannya dengan clients.openWindow() Compute Engine 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 kita ingin arahkan pengguna sudah terbuka atau belum. Dengan cara ini, kita dapat memfokuskan tab yang terbuka daripada membuka tab.

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 ditekankan bahwa hanya dapat dilakukan untuk halaman di origin Anda. Hal ini karena kita dapat hanya melihat halaman apa yang terbuka pada situs kita. Hal ini mencegah pengembang tidak dapat melihat semua situs yang dilihat oleh pengguna mereka.

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 urai halaman contoh menggunakan URL API. Ini adalah trik rapi yang saya ambil 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 bersifat absolut sehingga dapat dicocokkan dengan URL jendela di lain waktu.

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

Lalu, kita akan mendapatkan daftar objek WindowClient, yang merupakan daftar tab dan jendela yang sedang terbuka. (Ingat, tab ini hanya untuk origin Anda.)

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

Opsi yang diteruskan ke matchAll memberi tahu browser bahwa kita hanya ingin untuk menelusuri "window" ketik klien (yaitu hanya mencari tab dan jendela dan mengecualikan pekerja web). includeUncontrolled memungkinkan kita untuk menelusuri semua tab dari origin Anda yang tidak dikontrol oleh layanan saat ini yaitu pekerja layanan yang menjalankan kode ini. Umumnya, Anda akan selalu ingin includeUncontrolled bernilai true saat memanggil matchAll().

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

Saat promise matchAll() selesai, kita akan melakukan iterasi melalui klien jendela yang ditampilkan dan membandingkan URL mereka dengan URL yang ingin kita buka. Jika kami menemukan kecocokan, kita fokus pada klien, yang akan membawa jendela tersebut ke perhatian pengguna. Pemfokusan 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 penambahan tag ke notifikasi memilih untuk ikut serta dalam perilaku di mana notifikasi yang ada dengan tag yang sama akan diganti.

Namun Anda bisa menjadi lebih canggih dengan menciutkan notifikasi menggunakan API Notifikasi. Pertimbangkan aplikasi chat, yang developernya mungkin ingin notifikasi baru tampilkan pesan yang mirip dengan "Anda punya dua pesan dari Matt" bukan hanya menampilkan untuk membuat pesan email baru.

Anda dapat melakukannya, atau memanipulasi notifikasi saat ini dengan cara lain, menggunakan registration.getNotifications() API 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, anggaplah setiap notifikasi memiliki beberapa data yang mencakup nama pengguna.

Hal pertama yang perlu kita lakukan adalah menemukan notifikasi terbuka untuk pengguna dengan nama pengguna. Kita akan mendapatkan registration.getNotifications() dan menelusurinya 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.

Di aplikasi pesan palsu ini, kami akan melacak jumlah pesan baru dengan menambahkan hitungan pada pesan baru data notifikasi dan menambahnya pada 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 ditampilkan saat ini, kami menambah jumlah pesan dan mengatur judul notifikasi dan pesan isi secara tepat. Jika ada bukan ada notifikasi, kita membuat notifikasi baru dengan newMessageCount dari 1.

Hasilnya adalah pesan pertama akan terlihat seperti ini:

Notifikasi pertama tanpa penggabungan.

Notifikasi kedua akan menciutkan notifikasi menjadi ini:

Notifikasi kedua dengan penggabungan.

Hal yang menyenangkan dari pendekatan ini adalah jika pengguna Anda menyaksikan notifikasi yang saling muncul, akan terlihat dan terasa lebih kohesif selain mengganti pemberitahuan dengan pesan terbaru.

Pengecualian untuk aturan

Saya telah menyatakan bahwa Anda harus menunjukkan notifikasi saat menerima push dan ini adalah selalu benar . Satu skenario di mana Anda tidak perlu menampilkan notifikasi adalah saat pengguna membuka dan fokus pada situs Anda.

Di dalam peristiwa push, Anda dapat memeriksa apakah Anda perlu menampilkan notifikasi atau tidak dengan Memeriksa jendela klien dan mencari jendela yang terfokus.

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;
    });
}

Kami 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 menentukan 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);

Mengirimkan pesan ke halaman dari peristiwa push

Kami mendapati bahwa Anda tidak perlu menampilkan notifikasi jika pengguna sedang berada di situs Anda. Tapi bagaimana jika Anda masih ingin memberi tahu pengguna bahwa suatu peristiwa telah terjadi, tetapi ada 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 ketika notifikasi halus di halaman terlihat lebih baik dan lebih ramah bagi pengguna.

Katakanlah kita menerima {i>push<i}, memeriksa bahwa aplikasi web kita saat ini sedang fokus, maka kita bisa "{i>posting a message<i}" ke setiap halaman yang terbuka, seperti berikut:

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 peristiwa pesan pemroses:

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

Dalam pemroses pesan ini, Anda bisa melakukan apa pun yang Anda inginkan, menampilkan UI kustom pada laman Anda atau mengabaikan pesan sama sekali.

Perhatikan juga bahwa jika Anda tidak mendefinisikan pemroses pesan di laman web, pesan dari pekerja layanan tidak akan melakukan apa pun.

Menyimpan cache halaman dan membuka jendela

Satu skenario yang berada di luar cakupan panduan ini tetapi layak dibahas adalah bahwa Anda dapat meningkatkan UX aplikasi web Anda secara keseluruhan dengan menyimpan halaman web yang Anda harapkan akan dikunjungi pengguna mengklik notifikasi Anda.

Pekerja layanan Anda harus sudah disiapkan untuk menangani peristiwa fetch, tetapi jika Anda menerapkan pemroses peristiwa fetch, pastikan Anda melakukan manfaatkan di peristiwa push Anda 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 lebih lanjut, lihat pengantar pekerja layanan ini postingan Anda.

Langkah berikutnya

Lab kode