Sık kullanılan bildirim kalıpları

Matt Gaunt

Web Push ile ilgili bazı yaygın uygulama kalıplarına göz atacağız.

Bunun için, Service Worker'da bulunan farklı API'ler kullanılır.

Bildirim kapatma etkinliği

Son bölümde, notificationclick etkinliklerini nasıl dinleyebileceğimizi ele aldık.

Ayrıca, kullanıcı bildirimlerinizden birini kapatırsa (örneğin, kullanıcı bildirimi tıklamak yerine, artı işaretini tıklar veya bildirimi hızlıca kaydırırsa) çağrılan bir notificationclose etkinliği de vardır.

Bu etkinlik normalde kullanıcıların bildirimlerle etkileşimini izlemek amacıyla analizler için 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, yaygın olarak yalnızca kullanıcı bildirimi tıkladıysa yararlı olan veriler bulunur. Örneğin, bir bildirim tıklandığında açılması gereken URL.

Bir push etkinliğindeki verileri almanın ve bunu bir bildirime eklemenin en kolay yolu, showNotification() yöntemine geçirilen seçenekler 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

Bir bildirime verilen en yaygın yanıtlardan biri, belirli bir URL'ye yönlendiren bir pencere / sekme açmaktır. Bu işlemi clients.openWindow() API ile yapabiliriz.

notificationclick etkinliğimizde şunun 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 zaten 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 pencereyi odaklamalıyız.

Bunu nasıl başarabileceğinize bakmadan önce, bunun yalnızca kaynağınızdaki sayfalar için mümkün olduğunu vurgulamakta fayda vardır. Çünkü yalnızca sitemize ait açık olan sayfaları görebiliyoruz. Bu, geliştiricilerin, kullanıcılarının görüntülediği tüm siteleri görmelerini engeller.

Önceki örnekten devam edersek, /demos/notification-examples/example-page.html alanının zaten 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);

Şimdi, kodun üzerinden geçelim.

İlk olarak URL API'sını kullanarak örnek sayfamızı ayrıştırırız. Bu, Jeff Posnick'ten aldığım pratik bir numara. location nesnesiyle new URL() çağrıldığında, iletilen dize göreliyse (yani /, https://example.com/ haline gelirse) mutlak URL döndürür.

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

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

Daha sonra, şu anda açık olan sekme ve pencerelerin listesi olan WindowClient nesnelerinin bir listesini alırız. (Bunların yalnızca kaynağınıza ilişkin 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 (yani yalnızca sekmeleri ve pencereleri arayarak ve web çalışanlarını hariç tutmak) istediğimizi 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ızı sağlar. Genellikle, matchAll() çağrısı yaparken includeUncontrolled değerinin doğru olmasını istersiniz.

İade edilen sözü promiseChain olarak yakalarız. Böylece daha sonra event.waitUntil() hizmetine iletebilir ve hizmet çalışanlarımızı canlı tutabiliriz.

matchAll() vaadi çözümlendiğinde, döndürülen pencere istemcilerini yineler ve URL'lerini, açmak istediğimiz URL ile karşılaştırırız. Eşleşme bulunursa o müşteriye odaklanırız ve bu pencere kullanıcıların dikkatini çeker. matchingClient.focus() çağrısıyla odaklama tamamlanı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 bir bildirimin değiştirildiği bir davranışı etkinleştirdiğini gördük.

Bununla birlikte, Notifications API'yi kullanarak bildirimlerin daraltılması hakkında daha ayrıntılı bilgi edinebilirsiniz. Bir sohbet uygulamasını düşünün. Geliştiricinin, yalnızca en son mesajı göstermek yerine, "Met'ten iki mesajınız var" benzeri bir mesaj gösterecek yeni bir bildirim görmek isteyeceği bir uygulama düşünün.

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

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

Sohbet uygulamamızda, her bildirimin kullanıcı adı içeren birtakım veriler içerdiğini varsayalım.

Yapmak istediğimiz ilk şey, belirli bir kullanıcı adına sahip bir kullanıcıya ait açık bildirimleri bulmaktır. registration.getNotifications() kodunu alıp bunları döngüye alacağız ve notification.data içinde belirli bir kullanıcı adı olup olmadığını kontrol edeceğiz:

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

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

Bu sahte mesaj uygulamasında, yeni bildirim verilerimize bir sayı ekleyerek yeni mesaj sayısını izliyor ve her yeni bildirimle birlikte bu sayıyı artırıyoruz.

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

Görüntülenmekte olan bir bildirim varsa mesaj sayısını artırırız ve bildirim başlığı ile gövde mesajını buna göre ayarlarız. Bildirim yoksa newMessageCount/1 ile yeni bir bildirim oluştururuz.

Sonuç olarak ilk ileti aşağıdaki gibi görünür:

Birleştirmeden ilk bildirim.

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

Birleştirmeyle birlikte ikinci bildirim.

Bu yaklaşımın iyi tarafı, kullanıcınızın bildirimlerin birbiri üzerine göründüğüne şahit olması durumunda bildirimi en son mesajla değiştirmekten daha tutarlı görünmesidir.

Kural istisnası

Push aldığınızda bildirim göstermeniz gerektiğini belirtmiştim. Bu durum, çoğu zaman doğrudur. Bildirim göstermek zorunda kalmayacağınız tek senaryo, kullanıcının sitenizi açık ve odaklanmış olduğu zamandır.

Push etkinliğinizde, pencere istemcilerini inceleyerek ve odaklanılmış bir pencere arayarak bildirim göstermeniz gerekip gerekmediğini kontrol edebilirsiniz.

Tüm pencereleri almak ve odaklanmış bir pencere aramak için gereken kod şuna benzer:

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() kullanıyoruz ve ardından focused parametresini kontrol edip bunların üzerinden geçiyoruz.

Push etkinliğimizde bir bildirim göstermemize karar vermek için şu 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ı o sırada sitenizde bulunuyorsa bildirim göstermeyi atlayabileceğinizi fark ettik. Ancak, kullanıcıya bir etkinliğin gerçekleştiğini ancak bildirimin elle çok ağır davrandığını yine de bildirmek istiyorsanız ne olur?

Bu yaklaşımlardan biri, Service Worker'dan 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 küçük bir bildirimin kullanıcı için daha iyi ve daha dostça olduğu durumlarda faydalıdır.

Bir bildirim aldığımızı, web uygulamamızın şu anda odaklandığını kontrol ettiğimizi ve ardından her açık sayfaya aşağıdaki şekilde bir "mesaj yayınlayabileceğimizi" varsayalım:

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 birinde, bir mesaj etkinliği işleyici ekleyerek mesajları dinleriz:

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

Bu mesaj işleyicide, 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 işleyici tanımlamazsanız Service Worker'dan gelen mesajların hiçbir şey yapmayacağını unutmayın.

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

Bu kılavuzun kapsamı dışında kalan ancak tartışmaya değer bir senaryo, kullanıcıların bildiriminizi tıkladıktan sonra ziyaret etmelerini beklediğiniz web sayfalarını önbelleğe alarak web uygulamanızın genel kullanıcı deneyimini iyileştirebileceğinizdir.

Bunun için hizmet çalışanınızın fetch etkinliklerini işleyecek şekilde ayarlanması gerekir ancak bir fetch etkinlik işleyici uygularsanız bildirimi göstermeden önce sayfayı ve ihtiyacınız olacak öğeleri önbelleğe alarak push etkinliğinizde bundan yararlandığınızdan emin olun.

Tarayıcı uyumluluğu

notificationclose etkinliği

Tarayıcı Desteği

  • 50
  • 17
  • 44
  • 16

Kaynak

Clients.openWindow()

Tarayıcı Desteği

  • 40
  • 17
  • 44
  • 11.1

Kaynak

ServiceWorkerRegistration.getNotifications()

Tarayıcı Desteği

  • 40
  • 17
  • 44
  • 16

Kaynak

clients.matchAll()

Tarayıcı Desteği

  • 42
  • 17
  • 54
  • 11.1

Kaynak

Daha fazla bilgi için Service Worker'lara giriş konulu bu yayına göz atın.

Sonraki adımlar

Code Labs