Sık kullanılan bildirim kalıpları

Matt Gaunt

Web push için bazı yaygın uygulama kalıplarına göz atacağız.

Bu işlem için hizmet çalışanında bulunan birkaç farklı API'nin kullanılması gerekir.

Bildirim kapatma etkinliği

Son bölümde, notificationclick etkinliklerini nasıl dinleyebileceğinizi gördük.

Kullanıcı bildirimlerinizden birini kapatırsa (ör. bildirimi tıklamak yerine çarpıyı tıklar veya bildirimi kaydırarak kapatırsa) çağrılan bir notificationclose etkinliği de vardır.

Bu etkinlik, genellikle kullanıcıların bildirimlerle etkileşimini izlemek için analizlerde kullanılır.

self.addEventListener('notificationclose', function (event) {
  const dismissedNotification = event.notification;

  const promiseChain = notificationCloseAnalytics();
  event.waitUntil(promiseChain);
});

Bildirime veri ekleme

Bir push mesajı alındığında, yalnızca kullanıcı bildirimi tıkladıysa yararlı olan veriler olması yaygındır. Örneğin, bir bildirim tıklandığında açılması gereken URL.

Bir push etkinliğinden veri alıp bildirime eklemenin en kolay yolu, showNotification() içine iletilen options nesnesine bir data parametresi eklemektir. Örneğin:

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

Tıklama işleyici içinde verilere event.notification.data ile erişilebilir.

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('');

Pencere açma

Bildirimlere en yaygın yanıtlardan biri, belirli bir URL'ye yönlendiren bir pencere / sekme açmaktır. Bunu clients.openWindow() API'siyle yapabiliriz.

notificationclick etkinliğimizde aşağıdaki gibi bir kod çalıştırırız:

const examplePage = '/demos/notification-examples/example-page.html';
const promiseChain = clients.openWindow(examplePage);
event.waitUntil(promiseChain);

Bir sonraki bölümde, kullanıcıyı yönlendirmek istediğimiz sayfanın açık olup olmadığını nasıl kontrol edeceğimize bakacağız. Bu sayede, yeni sekmeler açmak yerine açık sekmeye odaklanabiliriz.

Mevcut bir pencereye odaklanma

Mümkün olduğunda, kullanıcı bir bildirimi her tıkladığında yeni bir pencere açmak yerine bir pencereye odaklanmalıyız.

Bu işlemi nasıl yapacağınıza göz atmadan önce, bunun yalnızca kaynağınızdaki sayfalar için mümkün olduğunu belirtmek isteriz. Bunun nedeni, yalnızca sitemize ait açık sayfaları görebilmemizdir. Bu, geliştiricilerin kullanıcılarının görüntülediği tüm siteleri görememesine neden olur.

Önceki örneği ele alalım. /demos/notification-examples/example-page.html'ün açık olup olmadığını görmek için kodu değiştireceğiz.

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

Kodu adım adım inceleyelim.

Öncelikle URL API'yi kullanarak örnek sayfamızı ayrıştırırız. Bu, Jeff Posnick'ten öğrendiğim güzel bir numara. İletilen dize göreliyse new URL()location nesnesi ile çağırmak mutlak bir URL döndürür (ör. /, https://example.com/ olur).

URL'yi daha sonra pencere URL'leriyle eşleştirebilmek için mutlak hale getiririz.

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

Ardından, WindowClient nesnelerinin listesini alırız. Bu liste, şu anda açık olan sekmelerin ve pencerelerin listesidir. (Bunların yalnızca kaynağınız için geçerli sekmeler olduğunu unutmayın.)

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

matchAll işlevine iletilen seçenekler, tarayıcıya yalnızca "pencere" türü istemcileri aramak istediğimizi (yani yalnızca sekmeleri ve pencereleri aramak ve web işleyicilerini hariç tutmak) bildirir. includeUncontrolled, kaynağınızdaki mevcut hizmet çalışanı (yani bu kodu çalıştıran hizmet çalışanı) tarafından kontrol edilmeyen tüm sekmeleri aramamızı sağlar. Genellikle, matchAll() işlevini çağırırken includeUncontrolled değerinin her zaman doğru olmasını istersiniz.

Döndürülen promise'ı promiseChain olarak yakalarız. Böylece, daha sonra hizmet işleyicimizi etkin tutarak event.waitUntil() içine iletebiliriz.

matchAll() vaadi çözüldüğünde, döndürülen pencere istemcileri arasında iterasyon yapar ve URL'lerini açmak istediğimiz URL ile karşılaştırırız. Eşleşme bulursak söz konusu istemciye odaklanırız. Bu da kullanıcının dikkatini söz konusu pencereye çeker. Odaklanma işlemi, matchingClient.focus() görüşmesi ile yapılır.

Eşleşen bir müşteri bulamazsak önceki bölümdekiyle aynı şekilde yeni bir pencere açarız.

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

Bildirimleri birleştirme

Bir bildirime etiket eklemenin, aynı etikete sahip mevcut bildirimlerin değiştirildiği bir davranışı etkinleştirdiğini fark ettik.

Ancak Notification API'yi kullanarak bildirimleri daraltarak daha gelişmiş bir deneyim sunabilirsiniz. Geliştiricinin, yeni bir bildirimde yalnızca son mesajı göstermek yerine "Murat'tan iki mesajınız var" gibi bir mesaj göstermek isteyebileceği bir sohbet uygulamasını düşünün.

Bunu yapabilir veya web uygulamanız için şu anda görünen tüm bildirimlere erişmenizi sağlayan registration.getNotifications() API'sini kullanarak mevcut bildirimleri başka şekillerde değiştirebilirsiniz.

Sohbet örneğini uygulamak için bu API'yi nasıl kullanabileceğimize bakalım.

Sohbet uygulamamızda her bildirimin bir kullanıcı adı içeren bazı verilere sahip olduğunu varsayalım.

İlk olarak, belirli bir kullanıcı adına sahip kullanıcının açık bildirimlerini bulacağız. registration.getNotifications() öğesini alırız ve bu öğeleri döngüden geçirip belirli bir kullanıcı adı için notification.data öğesini kontrol ederiz:

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

Sonraki adım, bu bildirimi yeni bir bildirimle değiştirmektir.

Bu sahte mesaj uygulamasında, yeni bildirimimizin verilerine bir sayı ekleyerek ve her yeni bildirimde bu sayıyı artırarak yeni mesajların sayısını izleriz.

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

Şu anda görüntülenen bir bildirim varsa mesaj sayısını artırırız ve bildirim başlığını ve gövde mesajını buna göre ayarlarız. Bildirim yoksa newMessageCount değeri 1 olan yeni bir bildirim oluştururuz.

Sonuç olarak, ilk mesaj şu şekilde görünür:

Birleştirilmemiş ilk bildirim.

İkinci bir bildirim, bildirimleri şu şekilde daraltır:

Birleştirmeyle ilgili ikinci bildirim.

Bu yaklaşımın avantajı, kullanıcınızın bildirimlerin üst üste göründüğünü görmesidir. Bu sayede, bildirimlerin en son mesajla değiştirilmesinden daha tutarlı bir görünüm ve his elde edilir.

Kuralın istisnası

Bir push aldığınızda bildirim göstermeniz zorunludur. Bu durum çoğu zaman geçerlidir. Bildirim göstermeniz gerekmeyen tek durum, kullanıcının sitenizi açık ve odaklı durumda bıraktığı durumdur.

Pencere istemcilerini inceleyip odaklanmış bir pencere arayarak push etkinliğinizde bildirim göstermeniz gerekip gerekmediğini kontrol edebilirsiniz.

Tüm pencereleri alma ve odaklanmış bir pencere arama kodu şu şekilde görünür:

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

Tüm pencere istemcilerimizi almak için clients.matchAll() değerini kullanırız ve ardından focused parametresini kontrol ederek bu istemciler arasında döngü yaparız.

Bildirim göstermemiz gerekip gerekmediğine karar vermek için push etkinliğimizde bu işlevi kullanırız:

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

Bir push etkinliğinden sayfaya mesaj gönderme

Kullanıcı şu anda sitenizdeyse bildirim göstermeyi atlayabilirsiniz. Ancak kullanıcıya bir olayın gerçekleştiğini bildirmek istiyorsanız ve bildirim çok ağırsa ne yapabilirsiniz?

Bir yaklaşım, hizmet çalışanından sayfaya mesaj göndermektir. Bu sayede web sayfası, kullanıcıya etkinlik hakkında bilgi veren bir bildirim veya güncelleme gösterebilir. Bu, sayfadaki belirsiz bir bildirimin kullanıcı için daha iyi ve daha samimi olduğu durumlarda kullanışlıdır.

Bir push aldığımız ve web uygulamamızın şu anda odaklandığını kontrol ettiğimiz varsayalım. Ardından, açık olan her sayfaya aşağıdaki gibi "mesaj yayınlayabiliriz":

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

Sayfaların her birine bir ileti etkinliği işleyici ekleyerek iletileri dinleriz:

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

Bu mesaj dinleyicisinde istediğiniz her şeyi yapabilir, sayfanızda özel bir kullanıcı arayüzü gösterebilir veya mesajı tamamen yoksayabilirsiniz.

Ayrıca, web sayfanızda bir mesaj dinleyici tanımlamazsanız hizmet çalışanından gelen mesajların hiçbir işe yaramayacağını da belirtmek isteriz.

Bir sayfayı önbelleğe alma ve pencere açma

Bu kılavuzun kapsamı dışında olmasına rağmen bahsetmeye değer bir senaryo, kullanıcıların bildiriminizi tıkladıktan sonra ziyaret etmesini beklediğiniz web sayfalarını önbelleğe alarak web uygulamanızın genel kullanıcı deneyimini iyileştirmektir.

Bunun için hizmet çalışanınızın fetch etkinliklerini işleyebilecek şekilde ayarlanması gerekir. Ancak bir fetch etkinlik dinleyicisi uygularsanız bildiriminizi göstermeden önce ihtiyacınız olan sayfayı ve öğeleri önbelleğe alarak push etkinliğinizde bu dinleyiciden yararlandığınızdan emin olun.

Tarayıcı uyumluluğu

notificationclose etkinliği

Tarayıcı desteği

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

Kaynak

Clients.openWindow()

Tarayıcı desteği

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

Kaynak

ServiceWorkerRegistration.getNotifications()

Tarayıcı desteği

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

Kaynak

clients.matchAll()

Tarayıcı desteği

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

Kaynak

Daha fazla bilgi için bu hizmet işçilerine giriş makalesine göz atın.

Sonraki adımlar

Codelab uygulamaları