Kullanıcının Abone Olması

Matt Gaunt

İlk adım, kullanıcıya push mesajları göndermek için izin almaktır. Sonrasında biz de bir PushSubscription cihazı alabiliriz.

Bunu yapacak JavaScript API makul derecede basittir, o yüzden mantık akışını inceleyelim.

Özellik algılama

İlk olarak, mevcut tarayıcının push mesajlaşmayı gerçekten destekleyip desteklemediğini kontrol etmemiz gerekir. Push'un desteklenip desteklenmediğini iki basit kontrolle kontrol edebiliriz.

  1. navigator'da serviceWorker'ı kontrol edin.
  2. window'da PushManager'ı kontrol edin.
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

Hizmet çalışanı ve push mesajları için tarayıcı desteği hızlı bir şekilde büyüse de, her iki özellik için de algılama özelliği ve aşamalı geliştirme yapmak her zaman iyi bir fikirdir.

Hizmet çalışanı kaydetme

Bu özellik algılama sayesinde hem Service Worker'ların hem de Push'un desteklendiğini biliyoruz. Bir sonraki adım, hizmet çalışanımızı "kaydetmek".

Bir hizmet çalışanı kaydettiğimizde tarayıcıya Service Worker dosyamızın nerede olduğunu bildiririz. Dosya hâlâ yalnızca JavaScript'tir ancak tarayıcı, push dahil olmak üzere Service Worker API'lerine "erişim izni verir". Daha kesin söylemek gerekirse, tarayıcı, dosyayı bir hizmet çalışanı ortamında çalıştırır.

Bir hizmet çalışanı kaydetmek için dosyamızın yolunu ileterek navigator.serviceWorker.register() çağrısı yapın. Örneğin:

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

Bu işlev, tarayıcıya bir Service Worker dosyamız olduğunu ve dosyanın konumunu bildirir. Bu durumda Service Worker dosyası /service-worker.js konumundadır. Perde arkasında tarayıcı, register() çağrısından sonra şu adımları uygular:

  1. Service Worker dosyasını indirin.

  2. JavaScript'i çalıştırın.

  3. Her şey doğru şekilde çalışırsa ve herhangi bir hata yoksa register() tarafından döndürülen söz çözümlenir. Herhangi bir hata olursa sözü reddedilecektir.

register() reddedilirse Chrome Geliştirici Araçları'nda JavaScript'inizde yazım hatası / hata olup olmadığını bir kez daha kontrol edin.

register() çözümlendiğinde ServiceWorkerRegistration döndürür. Bu kaydı PushManager API'ye erişmek için kullanırız.

PushManager API'si tarayıcı uyumluluğu

Tarayıcı Desteği

  • 42
  • 17
  • 44
  • 16

Kaynak

İzin isteniyor

Service Worker'ı kaydettik ve kullanıcıyı abone olmaya hazırız. Sonraki adım, kullanıcıdan push mesajları gönderme izni almaktır.

İzin almaya ilişkin API nispeten basittir. Bunun olumsuz tarafı, API'nin kısa süre önce geri çağırma yerine bir Promise döndürmeye geçiş yapmasıdır. Buradaki sorun, mevcut tarayıcı tarafından API'nın hangi sürümünün uygulandığını söyleyemememizdir. Bu nedenle, her ikisini de uygulamanız ve her ikisini de ele almanız gerekir.

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

Yukarıdaki kodda, önemli kod snippet'i Notification.requestPermission() çağrısıdır. Bu yöntemle kullanıcıya bir istem gösterilir:

Masaüstü ve mobil Chrome'da izin istemi.

Kullanıcı İzin Ver, Engelle'ye basarak veya yalnızca istemi kapatarak izin istemiyle etkileşimde bulunduğunda, sonuç şu şekilde bir dize olarak sunulur: 'granted', 'default' veya 'denied'.

Yukarıdaki örnek kodda, izin verilirse askPermission() tarafından döndürülen vade çözümlenir. Aksi takdirde, taahhüt reddine yönelik bir hata mesajı veririz.

İlgilenmeniz gereken nadir durumlardan biri, kullanıcının "Engelle" düğmesini tıklamasıdır. Böyle bir durumda web uygulamanız kullanıcıdan tekrar izin isteyemez. Kullanıcıların, izin durumunu değiştirerek uygulamanızın "engellemesini manuel olarak kaldırmaları" gerekir. İzin durumu ayarlar paneline gömülüdür. Kullanıcıdan nasıl ve ne zaman izin isteyeceğinizi dikkatle düşünün, çünkü kullanıcı engelle seçeneğini tıklarsa bu kararı geri almak kolay değildir.

İyi haber ise çoğu kullanıcı iznin neden istendiğini bildikleri sürece izin vermekten mutluluk duymasıdır.

Bazı popüler sitelerin nasıl izin istediğine daha sonra bakacağız.

PushManager ile bir kullanıcıya abone olma

Hizmet çalışanımızı kaydettirdikten ve izin aldıktan sonra registration.pushManager.subscribe() numaralı telefonu arayarak bir kullanıcıyı abone olabiliriz.

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

subscribe() yöntemini çağırırken hem gerekli hem de isteğe bağlı parametrelerden oluşan bir options nesnesi geçiririz.

Sunabileceğimiz tüm seçeneklere bakalım.

uservisibleOnly seçenekleri

Push mesajı tarayıcılara ilk eklendiğinde, geliştiricilerin push mesajı gönderip bildirim göstermemelerinin mümkün olup olmadığı konusunda bir belirsizlik vardı. Kullanıcının arka planda bir şey olduğunu anlamadığı için buna genellikle sessiz push denir.

Buradaki sorun, geliştiricilerin, bir kullanıcının konumunu kullanıcının haberi olmadan sürekli olarak izlemesi gibi can sıkıcı şeyler yapabiliyor olmasıydı.

Bu senaryodan kaçınmak ve spesifikasyon yazarlarına bu özelliği en iyi nasıl destekleyeceklerini düşünmeleri için zaman tanımak amacıyla userVisibleOnly seçeneği eklendi ve tarayıcıyla true değerinin iletilmesi, her push geldiğinde web uygulamasının bildirim göstereceği (yani sessiz push olmadığı) sembolik bir anlaşmadır.

Şu anda true değerini geçirmeniz gerekmektedir. userVisibleOnly anahtarını dahil etmezseniz veya false içinde geçirmezseniz aşağıdaki hatayı alırsınız:

Chrome, şu anda yalnızca kullanıcıların görebileceği mesajlarla sonuçlanacak abonelikler için Push API'sini desteklemektedir. Bunun yerine pushManager.subscribe({userVisibleOnly: true}) yöntemini çağırarak bunu belirtebilirsiniz. Daha fazla bilgi için https://goo.gl/yqv4Q4 adresine göz atın.

Şu anda Chrome'da hiçbir zaman genel sessiz push uygulanmayacak gibi görünüyor. Bunun yerine, teknik özellik yazarları web uygulamalarına bir web uygulamasının kullanımına bağlı olarak belirli sayıda sessiz push mesajı izni verecek bir bütçe API'si kavramını keşfetmektedir.

applicationServerKey (uygulama Sunucusu Anahtarı) seçeneği

Bir önceki bölümde kısaca "uygulama sunucusu anahtarları"ndan bahsetmiştik. "Uygulama sunucusu anahtarları", bir push hizmeti tarafından kullanıcıya abone olan uygulamayı tanımlamak ve aynı uygulamanın bu kullanıcıya mesaj göndermesini sağlamak için kullanılır.

Uygulama sunucusu anahtarları, uygulamanıza özgü genel ve özel anahtar çiftidir. Özel anahtar, uygulamanızda gizli tutulmalıdır ve ortak anahtar serbestçe paylaşılabilir.

subscribe() çağrısına iletilen applicationServerKey seçeneği, uygulamanın ortak anahtarıdır. Tarayıcı, kullanıcıya abone olurken bunu bir push hizmetine aktarır. Yani push hizmeti, uygulamanızın ortak anahtarını kullanıcının PushSubscription hizmetine bağlayabilir.

Aşağıdaki şemada bu adımlar gösterilmektedir.

  1. Web uygulamanız bir tarayıcıda yüklenir ve herkese açık uygulama sunucusu anahtarınızı ileterek subscribe() çağırırsınız.
  2. Ardından tarayıcı, bir push hizmetine ağ isteği gönderir. Söz konusu hizmet, uç nokta oluşturur, bu uç noktayı uygulamanın ortak anahtarıyla ilişkilendirir ve bu uç noktayı tarayıcıya döndürür.
  3. Tarayıcı bu uç noktayı, subscribe() sözüyle döndürülen PushSubscription öğesine ekler.

Ortak uygulama sunucusu anahtarının, abone olma yönteminde kullanıldığını gösteren görsel.

Daha sonra bir push iletisi göndermek istediğinizde, uygulama sunucunuzun özel anahtarı ile imzalanan bilgileri içeren bir Yetkilendirme üstbilgisi oluşturmanız gerekir. Push hizmeti push mesajı gönderme isteği aldığında, isteği alan uç noktaya bağlı ortak anahtarı arayarak bu imzalı Yetkilendirme üst bilgisini doğrulayabilir. İmza geçerliyse push hizmeti, eşleşen özel anahtarla uygulama sunucusundan gelmiş olması gerektiğini bilir. Bu temelde başka kişilerin, uygulamanın kullanıcılarına ileti göndermesini engelleyen bir güvenlik önlemidir.

İleti gönderirken özel uygulama sunucusu anahtarının
nasıl kullanıldığı

Teknik olarak, applicationServerKey isteğe bağlıdır. Ancak, Chrome'daki en kolay uygulama gerekir. Diğer tarayıcılar da gelecekte gerekli olabilir. Firefox'ta isteğe bağlıdır.

Uygulama sunucusu anahtarının ne olması gerektiğini tanımlayan spesifikasyon VAPID spesifikasyonudur. "uygulama sunucusu anahtarları" veya "VAPID anahtarları" ile ilgili bir şey okuduğunuzda bunların aynı olduğunu unutmayın.

Uygulama sunucusu anahtarları nasıl oluşturulur?

web-push-codelab.glitch.me adresini ziyaret ederek genel ve özel bir uygulama sunucusu anahtarı grubu oluşturabilir veya aşağıdakileri yaparak anahtar oluşturmak için web-push komut satırını kullanabilirsiniz:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

Bu anahtarları uygulamanız için yalnızca bir kez oluşturmanız yeterlidir. Özel anahtarı gizli tuttuğunuzdan emin olun. (Evet, az önce dedim.)

İzinler ve abone ol()

subscribe() çağrısının bir yan etkisi vardır. Web uygulamanızın subscribe() çağrısı sırasında bildirimleri gösterme izni yoksa tarayıcı sizin için bu izinleri ister. Kullanıcı arayüzünüz bu akışla çalışıyorsa bu özellik yararlıdır ancak daha fazla kontrol istiyorsanız (çoğu geliştiricinin bunu yapacağını düşünüyorum) daha önce kullandığımız Notification.requestPermission() API'ye bağlı kalın.

Push Aboneliği nedir?

subscribe() adını veriyor ve bazı seçenekleri iletiyoruz. Bunun karşılığında, PushSubscription ile sonuçlanacak ve aşağıdakine benzer bir kodla sonuçlanacak bir taahhüt alıyoruz:

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

PushSubscription nesnesi, söz konusu kullanıcıya push mesajları göndermek için gereken tüm bilgileri içerir. İçeriği JSON.stringify() kullanarak yazdırırsanız şunları görürsünüz:

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint, push hizmetleri URL'sidir. Push mesajını tetiklemek için bu URL'ye POST isteği gönderin.

keys nesnesi, push mesajıyla gönderilen mesaj verilerini şifrelemek için kullanılan değerleri içerir (bu konuyu bu bölümün ilerleyen kısımlarında ele alacağız).

Sunucunuza abonelik gönderme

Push aboneliğiniz olduğunda bunu sunucunuza göndermek istersiniz. Bunu nasıl yapacağınıza siz karar verirsiniz. Ancak küçük bir ipucu olarak, gerekli tüm verileri abonelik nesnesinden almak için JSON.stringify() kullanmanız gerekebilir. Alternatif olarak aynı sonucu manuel olarak bir araya getirebilirsiniz. Örneğin:

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(pushSubscription);

Aboneliğin gönderilmesi web sayfasında aşağıdaki şekilde yapılır:

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

Düğüm sunucusu bu isteği alır ve verileri daha sonra kullanılmak üzere bir veritabanına kaydeder.

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  return saveSubscriptionToDatabase(req.body)
    .then(function (subscriptionId) {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify({data: {success: true}}));
    })
    .catch(function (err) {
      res.status(500);
      res.setHeader('Content-Type', 'application/json');
      res.send(
        JSON.stringify({
          error: {
            id: 'unable-to-save-subscription',
            message:
              'The subscription was received but we were unable to save it to our database.',
          },
        }),
      );
    });
});

Sunucumuzdaki PushSubscription ayrıntılarıyla kullanıcımıza istediğimiz zaman bir mesaj gönderebiliriz.

SSS

Bu noktada kullanıcıların sıkça sorduğu sorulardan birkaçı:

Tarayıcının kullandığı push hizmetini değiştirebilir miyim?

Hayır. Push hizmeti tarayıcı tarafından seçilir ve subscribe() çağrısında gördüğümüz gibi, tarayıcı PushSubscription'ni oluşturan ayrıntıları almak için push hizmetine ağ isteği gönderir.

Her tarayıcı farklı bir Push Hizmeti kullanıyor, farklı API'ları yok mu?

Tüm push hizmetlerinde aynı API kullanılır.

Bu ortak API'ye Web Gönderme Protokolü denir ve uygulamanızın push mesajını tetiklemek için yapması gereken ağ isteğini açıklar.

Bir kullanıcıya masaüstü bilgisayarında abone olursam bu kullanıcı telefonunda da abone olur mu?

Maalesef hayır. Kullanıcı, mesajları almak istediği her tarayıcıda push için kaydolmalıdır. Bunun için kullanıcının her cihazda izin vermesinin gerekeceğini de unutmamak gerekir.

Sonraki adımlar

Code Labs