Subskrybowanie użytkownika w celu otrzymywania powiadomień push

Aby wysyłać wiadomości push, musisz najpierw uzyskać zgodę użytkownika, a następnie zasubskrybować jego urządzenie w usłudze push. Wymaga to użycia interfejsu JavaScript API do uzyskania obiektu PushSubscription, który następnie wysyłasz na serwer.

Interfejs JavaScript API zarządza tym procesem w prosty sposób. W tym przewodniku znajdziesz opis całego procesu, w tym wykrywania funkcji, proszenia o uprawnienia i zarządzania subskrypcją.

Wykrywanie cech

Najpierw sprawdź, czy przeglądarka obsługuje wiadomości push. Obsługę powiadomień push możesz sprawdzić na 2 sposoby:

  • Sprawdź, czy w obiekcie navigator znajduje się serviceWorker.
  • Sprawdź, czy w obiekcie window znajduje się PushManager.
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;
}

Obsługa zarówno service workerów, jak i wiadomości push w przeglądarkach jest coraz lepsza, ale zawsze wykrywaj obie funkcje i stopniowo ulepszaj aplikację.

Rejestrowanie skryptu service worker

Po wykryciu funkcji wiesz, że usługa Service Worker i wiadomości push są obsługiwane. Następnie zarejestruj skrypt service worker.

Podczas rejestrowania service workera podajesz przeglądarce lokalizację pliku service workera. Jest to plik JavaScript, ale przeglądarka przyznaje mu dostęp do interfejsów API service workera, w tym do wiadomości push. Przeglądarka uruchamia plik w środowisku instancji roboczej usługi.

Aby zarejestrować service worker, wywołaj funkcję navigator.serviceWorker.register() i przekaż ścieżkę do pliku. Na przykład:

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

Ta funkcja informuje przeglądarkę o lokalizacji pliku service worker. W tym przypadku plik service workera znajduje się w lokalizacji /service-worker.js. Po wywołaniu funkcji register() przeglądarka wykonuje te czynności:

  1. Pobierz plik service worker.

  2. Uruchom JavaScript.

  3. Jeśli plik działa prawidłowo i nie zawiera błędów, obietnica zwrócona przez register() zostanie spełniona. Jeśli wystąpią błędy, obietnica zostanie odrzucona.

Uwaga: jeśli register() odrzuci żądanie, sprawdź, czy w kodzie JavaScript nie ma błędów lub literówek, korzystając z Narzędzi deweloperskich w Chrome.

Gdy register() zostanie rozwiązany, zwraca ServiceWorkerRegistration. Ta rejestracja umożliwia dostęp do interfejsu PushManager API.

Zgodność przeglądarek z interfejsem PushManager API

Browser Support

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

Source

Wysyłanie prośby o uprawnienia

Po zarejestrowaniu procesu roboczego usługi i uzyskaniu uprawnień poproś użytkownika o zgodę na wysyłanie wiadomości push.

Interfejs API do uzyskiwania uprawnień jest prosty. Jednak interfejs API został niedawno zmieniony z wywoływania zwrotnego na zwracanie obietnicy. Nie możesz określić, którą wersję interfejsu API implementuje przeglądarka, więc musisz zaimplementować i obsługiwać obie wersje.

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

W powyższym kodzie wywołanie funkcji Notification.requestPermission() wyświetla użytkownikowi prośbę:

Prośba o zezwolenie wyświetlana w Chrome na komputerach i urządzeniach mobilnych.

Gdy użytkownik wejdzie w interakcję z prośbą o uprawnienia, klikając Zezwól, Zablokuj lub zamykając ją, otrzymasz wynik w postaci ciągu znaków: 'granted', 'default' lub 'denied'.

W przykładowym kodzie obietnica zwrócona przez askPermission() jest spełniana, jeśli uprawnienia zostaną przyznane. W przeciwnym razie zgłasza błąd i jest odrzucana.

Obsłuż przypadek, w którym użytkownik kliknie przycisk Zablokuj. W takim przypadku aplikacja internetowa nie może ponownie poprosić użytkownika o zezwolenie. Użytkownik musi ręcznie odblokować aplikację, zmieniając jej stan uprawnień w panelu ustawień. Zastanów się, kiedy i jak poprosić o zgodę, ponieważ jeśli użytkownik kliknie Zablokuj, trudno będzie cofnąć tę decyzję.

Większość użytkowników przyznaje uprawnienia, jeśli rozumie, dlaczego aplikacja o nie prosi.

W dalszej części tego dokumentu opisujemy, jak niektóre popularne witryny proszą o zezwolenie.

Subskrybowanie użytkownika za pomocą interfejsu PushManager

Po zarejestrowaniu komponentu service worker i uzyskaniu uprawnień możesz zasubskrybować użytkownika, wywołując funkcję registration.pushManager.subscribe().

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

Gdy wywołujesz metodę subscribe(), przekazujesz obiekt options, który składa się z parametrów wymaganych i opcjonalnych.

W tej sekcji opisujemy opcje, które możesz przekazywać.

opcje userVisibleOnly

Gdy wiadomości push zostały po raz pierwszy dodane do przeglądarek, deweloperzy nie byli pewni, czy można wysyłać wiadomości push bez wyświetlania powiadomienia. Jest to zwykle nazywane cichym powiadomieniem push, ponieważ użytkownik nie wie, że w tle wystąpiło zdarzenie.

Obawiano się, że deweloperzy mogą śledzić lokalizację użytkownika w sposób ciągły bez jego wiedzy.

Aby uniknąć takiej sytuacji i umożliwić autorom specyfikacji rozważenie, jak najlepiej obsługiwać tę funkcję, dodaliśmy opcję userVisibleOnly. Przekazanie wartości true jest symbolicznym potwierdzeniem dla przeglądarki, że aplikacja internetowa będzie wyświetlać powiadomienie za każdym razem, gdy otrzyma wiadomość push (czyli nie będzie to ciche powiadomienie push).

Musisz przekazać wartość true. Jeśli nie podasz klucza userVisibleOnly lub nie przekażesz wartości false, pojawi się ten błąd:

Chrome currently only supports the Push API for subscriptions that will result
in user-visible messages. You can indicate this by calling
`pushManager.subscribe({userVisibleOnly: true})` instead. See
[https://goo.gl/yqv4Q4](https://goo.gl/yqv4Q4) for more details.

Chrome obsługuje interfejs Push API tylko w przypadku subskrypcji, które generują wiadomości widoczne dla użytkownika. Zgłoś to, dzwoniąc pod numer pushManager.subscribe({userVisibleOnly: true}). Więcej informacji znajdziesz na stronie https://goo.gl/yqv4Q4.

Wygląda na to, że w Chrome nie zostanie wdrożone globalne wyciszanie powiadomień push. Zamiast tego autorzy specyfikacji pracują nad interfejsem Budget API, który umożliwia aplikacjom internetowym wysyłanie określonej liczby cichych powiadomień push na podstawie sposobu korzystania z aplikacji internetowej.

opcja applicationServerKey

W tym dokumencie wcześniej wspominaliśmy o kluczach serwera aplikacji. Usługa push używa kluczy serwera aplikacji do identyfikowania aplikacji, która subskrybuje użytkownika, i zapewnia, że ta sama aplikacja wysyła do niego wiadomości.

Klucze serwera aplikacji to para kluczy publicznego i prywatnego, które są unikalne dla Twojej aplikacji. Klucz prywatny powinien być znany tylko Twojej aplikacji, a klucz publiczny możesz udostępniać bez ograniczeń.

Opcja applicationServerKey przekazana do wywołania subscribe() to klucz publiczny aplikacji. Przeglądarka przekazuje ten klucz do usługi push podczas subskrybowania użytkownika, co umożliwia usłudze push powiązanie klucza publicznego aplikacji z PushSubscription użytkownika.

Poniższy diagram ilustruje te kroki.

  1. Załaduj aplikację internetową w przeglądarce i wywołaj funkcję subscribe(), przekazując publiczny klucz serwera aplikacji.
  2. Przeglądarka wysyła następnie żądanie sieciowe do usługi push, która generuje punkt końcowy, kojarzy go z kluczem publicznym aplikacji i zwraca go do przeglądarki.
  3. Przeglądarka dodaje ten punkt końcowy do PushSubscription, który zwraca obietnica subscribe().

Diagram ilustrujący sposób użycia klucza publicznego serwera aplikacji w metodzie `subscribe()`.

Gdy wysyłasz wiadomość push, utwórz nagłówek Authorization, który zawiera informacje podpisane kluczem prywatnym serwera aplikacji. Gdy usługa push otrzyma żądanie wysłania wiadomości push, sprawdzi podpisany nagłówek Authorization, wyszukując klucz publiczny powiązany z punktem końcowym, który otrzymał żądanie. Jeśli podpis jest prawidłowy, usługa push wie, że żądanie pochodzi z serwera aplikacji z odpowiednim kluczem prywatnym. Jest to środek bezpieczeństwa, który uniemożliwia innym osobom wysyłanie wiadomości do użytkowników Twojej aplikacji.

Diagram ilustrujący, jak klucz serwera aplikacji prywatnej jest używany podczas wysyłania wiadomości.

Technicznie rzecz biorąc, applicationServerKey jest opcjonalny. Jednak najprostsza implementacja w Chrome wymaga tego, a inne przeglądarki mogą wymagać tego w przyszłości. W przypadku Firefoksa jest to opcjonalne.

Klucz serwera aplikacji jest zdefiniowany w specyfikacji VAPID. Gdy zobaczysz odniesienia do kluczy serwera aplikacji lub kluczy VAPID, pamiętaj, że są one takie same.

Tworzenie kluczy serwera aplikacji

Możesz utworzyć publiczny i prywatny zestaw kluczy serwera aplikacji, odwiedzając stronę web-push-codelab.glitch.me lub używając wiersza poleceń web-push do wygenerowania kluczy w ten sposób:

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

Klucze te należy utworzyć tylko raz dla aplikacji i zadbać o to, aby klucz prywatny pozostał prywatny.

Uprawnienia i metoda subscribe()

Wywołanie funkcji subscribe() ma jeden skutek uboczny. Jeśli aplikacja internetowa nie ma uprawnień do wyświetlania powiadomień, gdy wywołujesz funkcję subscribe(), przeglądarka poprosi Cię o przyznanie tych uprawnień. Jest to przydatne, jeśli interfejs użytkownika działa w tym przepływie, ale jeśli chcesz mieć większą kontrolę (co jest celem większości programistów), użyj interfejsu Notification.requestPermission() API, o którym wspominaliśmy wcześniej.

Omówienie PushSubscription

Dzwonisz pod numer subscribe(), przekazujesz opcje i otrzymujesz obietnicę, która prowadzi do PushSubscription. Na przykład:

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

Obiekt PushSubscription zawiera wszystkie informacje potrzebne do wysyłania do użytkownika wiadomości push. Jeśli wydrukujesz zawartość za pomocą JSON.stringify(), zobaczysz:

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

endpoint to URL usługi push. Aby wywołać wiadomość push, wyślij żądanie POST na ten adres URL.

Obiekt keys zawiera wartości używane do szyfrowania danych wiadomości wysyłanych za pomocą wiadomości push. (Szyfrowanie wiadomości omówimy w dalszej części tego dokumentu).

Wysyłanie subskrypcji na serwer

Po uzyskaniu subskrypcji push wyślij ją na serwer. Sposób wysyłania zależy od Ciebie, ale zalecamy użycie JSON.stringify(), aby wyodrębnić wszystkie niezbędne dane z obiektu subskrypcji. Możesz też ręcznie uzyskać ten sam wynik, np.:

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

Aby wysłać subskrypcję ze strony internetowej, użyj tego kodu:

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

Serwer Node.js odbiera to żądanie i zapisuje dane w bazie danych do późniejszego wykorzystania.

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

Dzięki szczegółowym informacjom PushSubscription na serwerze możesz w każdej chwili wysłać użytkownikowi wiadomość.

Regularnie odnawiaj subskrypcję, aby zapobiec jej wygaśnięciu

Podczas subskrybowania powiadomień push często otrzymujesz PushSubscription.expirationTime null. Teoretycznie oznacza to, że subskrypcja nigdy nie wygasa. (DOMHighResTimeStamp oznacza dokładny czas wygaśnięcia). W praktyce jednak przeglądarki często pozwalają na wygaśnięcie subskrypcji. Może się to zdarzyć np. wtedy, gdy przez dłuższy czas nie są odbierane powiadomienia push lub gdy przeglądarka wykryje, że użytkownik nie korzysta z aplikacji, która ma uprawnienia do wysyłania powiadomień push. Jednym ze sposobów zapobiegania temu problemowi jest ponowne subskrybowanie użytkownika po otrzymaniu każdego powiadomienia, jak pokazano w poniższym fragmencie kodu. Wymaga to częstego wysyłania powiadomień, aby zapobiec automatycznemu wygaśnięciu subskrypcji w przeglądarce. Należy dokładnie rozważyć zalety i wady uzasadnionych potrzeb związanych z powiadomieniami w porównaniu z niechcianym spamowaniem użytkownika wyłącznie w celu zapobiegania wygaśnięciu subskrypcji. Nie należy próbować obejść działań przeglądarki mających na celu ochronę użytkownika przed dawno zapomnianymi subskrypcjami powiadomień.

/* In the Service Worker. */

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag
    })
  );

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

Najczęstsze pytania

Oto kilka najczęstszych pytań:

Czy można zmienić usługę push, z której korzysta przeglądarka?

Nie, to przeglądarka wybiera usługę push. Jak wspomnieliśmy w sekcji dotyczącej wywołania subscribe(), przeglądarka wysyła żądania sieciowe do usługi push, aby pobrać szczegóły, które składają się na PushSubscription.

Czy różne usługi push korzystają z różnych interfejsów API?

Wszystkie usługi push oczekują tego samego interfejsu API.

Ten wspólny interfejs API, zwany protokołem Web Push, opisuje żądanie sieciowe, które aplikacja wysyła w celu wywołania wiadomości push.

Jeśli zasubskrybuję użytkownika na komputerze, czy będzie on subskrybowany również na telefonie?

Nie. Użytkownik musi zarejestrować się w usłudze wiadomości push w każdej przeglądarce, w której chce otrzymywać wiadomości. Wymaga to też przyznania uprawnień przez użytkownika na każdym urządzeniu.

Dalsze kroki

Codelabs