Sık kullanılan bildirim kalıpları

Matt Gaunt

Web aktarımı için yaygın olarak kullanılan bazı 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.

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ç

Bildirimlere en sık verilen yanıtlardan biri, belirli bir URL'ye yönlendiren bir pencere/sekme açmaktır. Bunu clients.openWindow() API ile 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 şekilde, 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.

Bunu nasıl yapacağınıza bakmadan önce, bunun yalnızca kaynaktaki sayfalar için mümkün olduğunu vurgulamak isteriz. Bunun nedeni, yalnızca sitemize ait olan açık sayfaların hangileri olduğunu görebilmemizdir. Bu durum, geliştiricilerin, kullanıcılarının görüntülediği tüm siteleri görmesini engeller.

Ö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'sini 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).

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

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

Ardından, şu anda açık olan sekme ve pencerelerin listesi olan WindowClient nesnelerinin bir listesini alırız. (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ızda mevcut hizmet çalışanı (bu kodu çalıştıran hizmet çalışanı) tarafından kontrol edilmeyen tüm sekmeleri aramamıza olanak tanır. 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() sözü yerine getirildiğinde, döndürülen pencere istemcilerindeki adımları tekrarlar ve bunların 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ümde olduğu gibi 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 tüm bildirimlerin değiştirildiği bir davranışı etkinleştirdiğini gördük.

Ancak Notifications API'yi kullanarak bildirimleri daraltarak daha sofistike hale getirebilirsiniz. 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.

Web uygulamanız için görünür durumda olan tüm bildirimlere erişmenizi sağlayan registration.getNotifications() API'sini kullanarak bunu yapabilir veya mevcut bildirimleri başka şekillerde değiştirebilirsiniz.

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

Sohbet uygulamamızda her bildirimde kullanıcı adı da dahil bazı verilerin olduğunu varsayalım.

İlk olarak, belirli bir kullanıcı adına sahip kullanıcının açık bildirimlerini bulacağız. registration.getNotifications() değerini alırız ve bu değerleri döngüden geçirip belirli bir kullanıcı adı için notification.data değerini 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ımda bu bildirimi yeni bir bildirimle değiştirmeniz gerekir.

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ştirme içermeyen ilk bildirim.

İkinci bir bildirim ise 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.

Push etkinliğimizde bir bildirim göstermemiz gerekip gerekmediğine karar vermek için 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);

Push etkinliğinden bir 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.
  • Kenar: 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.

Yakında gidilecek yerler

Codelab uygulamaları