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 w celu uzyskania obiektu PushSubscription, który następnie wysyłasz na serwer.

Interfejs JavaScript API zarządza tym procesem w prosty sposób. Ten przewodnik wyjaśnia cały proces, w tym wykrywanie funkcji, prośbę o przyznanie uprawnień i zarządzanie procesem subskrypcji.

Wykrywanie funkcji

Najpierw sprawdź, czy przeglądarka obsługuje wiadomości push. Możesz sprawdzić, czy obsługiwane są powiadomienia push, wykonując 2 testy:

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

Chociaż obsługa skryptów service worker i wiadomości push w przeglądarkach jest coraz powszechniejsza, zawsze wykrywaj obie funkcje i stopniowo ulepszaj aplikację.

Rejestrowanie skryptu service worker

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

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

Aby zarejestrować skrypt service worker, wywołaj navigator.serviceWorker.register() i podaj ś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 skryptu service worker. W tym przypadku plik skryptu service worker znajduje się w /service-worker.js. Po wywołaniu metody register() przeglądarka wykonuje te czynności:

  1. Pobierz plik skryptu service worker.

  2. Uruchom JavaScript.

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

Uwaga: jeśli register() odrzuci żądanie, sprawdź kod JavaScript pod kątem literówek lub błędów w Narzędziach deweloperskich w Chrome.

Gdy register() zostanie rozwiązany, zwraca ServiceWorkerRegistration. Ta rejestracja służy do uzyskiwania dostępu do interfejsu PushManager API.

Zgodność interfejsu PushManager API z przeglądarkami

Browser Support

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

Source

Wysyłanie prośby o uprawnienia

Po zarejestrowaniu skryptu service worker 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 i zamiast wywołania zwrotnego zwraca obiekt Promise. Nie możesz określić, którą wersję interfejsu API implementuje przeglądarka, dlatego 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 Notification.requestPermission() wyświetla użytkownikowi prośbę:

Prośba o przyznanie uprawnień wyświetlana w Chrome na komputerze i urządzeniu mobilnym.

Gdy użytkownik wejdzie w interakcję z prośbą o przyznanie uprawnień, wybierają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 zwracana przez askPermission() jest spełniana, jeśli uprawnienie zostało przyznane. W przeciwnym razie występuje błąd i obietnica zostaje odrzucona.

Obsłuż skrajny przypadek, w którym użytkownik klika przycisk Zablokuj. W takim przypadku aplikacja internetowa nie może ponownie poprosić użytkownika o przyznanie uprawnień. Użytkownik musi ręcznie odblokować aplikację, zmieniając stan jej uprawnień w panelu ustawień. Zastanów się, kiedy i jak poprosić o uprawnienia, ponieważ jeśli użytkownik kliknie Zablokuj, cofnięcie tej decyzji nie będzie łatwe.

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

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

Subskrybowanie użytkownika za pomocą PushManager

Po zarejestrowaniu skryptu service worker i uzyskaniu uprawnień możesz zasubskrybować użytkownika, wywołując 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 wymaganych i opcjonalnych parametrów.

W tej sekcji opisano opcje, które możesz przekazać.

Opcje userVisibleOnly

Gdy po raz pierwszy dodano do przeglądarek wiadomości push, deweloperzy nie byli pewni, czy wysyłać wiadomości push bez wyświetlania powiadomienia. Jest to powszechnie nazywane cichym powiadomieniem push, ponieważ użytkownik nie wie, że zdarzenie miało miejsce w tle.

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

Aby uniknąć tego scenariusza i umożliwić autorom specyfikacji rozważenie, jak najlepiej obsługiwać tę funkcję, dodano opcję userVisibleOnly. Przekazanie wartości true jest symboliczną zgodą na to, że aplikacja internetowa będzie wyświetlać powiadomienie za każdym razem, gdy otrzyma wiadomość push (czyli nie będzie to cicha wiadomość push).

Musisz przekazać wartość true. Jeśli nie podasz klucza userVisibleOnly lub przekażesz wartość 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 powodują wyświetlanie wiadomości widocznych dla użytkowników. Wskaż to, wywołując funkcję 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 ogólne wyciszanie powiadomień push. Zamiast tego autorzy specyfikacji badają interfejs API budżetu, który umożliwia aplikacjom internetowym wysyłanie określonej liczby cichych powiadomień push na podstawie wykorzystania aplikacji internetowej.

Opcja applicationServerKey

W tym dokumencie wspomniano wcześniej o kluczach serwera aplikacji. Usługa push używa kluczy serwera aplikacji do identyfikowania aplikacji, którą subskrybuje użytkownik, i do upewnienia się, że ta sama aplikacja wysyła wiadomości do użytkownika.

Klucze serwera aplikacji to para kluczy publicznego i klucza prywatnego, która jest unikalna dla Twojej aplikacji. Klucz prywatny powinien być znany tylko Twojej aplikacji, a klucz publiczny można udostępniać bez ograniczeń.

Opcja applicationServerKey przekazywana 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.

Te kroki przedstawia poniższy diagram.

  1. Wczytaj aplikację internetową w przeglądarce i wywołaj subscribe(), przekazując klucz publiczny serwera aplikacji.
  2. Przeglądarka wysyła żądanie sieciowe do usługi push, która generuje punkt końcowy, powiązuje go z kluczem publicznym aplikacji i zwraca punkt końcowy do przeglądarki.
  3. Przeglądarka dodaje ten punkt końcowy do obiektu 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 otrzymuje żądanie wysłania wiadomości push, sprawdza podpisany nagłówek Authorization, wyszukując klucz publiczny powiązany z punktem końcowym, który otrzymuje żądanie. Jeśli podpis jest prawidłowy, usługa push wie, że żądanie pochodzi z serwera aplikacji z odpowiednim kluczem prywatnym. Jest to zabezpieczenie, które uniemożliwia innym osobom wysyłanie wiadomości do użytkowników Twojej aplikacji.

Diagram ilustrujący, jak klucz prywatny serwera aplikacji 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ą tego wymagać w przyszłości. W przypadku Firefoksa jest to opcjonalne.

Specyfikacja VAPID definiuje klucz serwera aplikacji. Gdy zobaczysz odniesienia do kluczy serwera aplikacji lub kluczy VAPID, pamiętaj, że są to te same klucze.

Tworzenie kluczy serwera aplikacji

Możesz utworzyć publiczny i prywatny zestaw kluczy serwera aplikacji, używając wiersza poleceń web-push do wygenerowania kluczy w ten sposób:

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

Utwórz te klucze tylko raz dla swojej aplikacji i upewnij się, że klucz prywatny jest przechowywany w bezpiecznym miejscu.

Uprawnienia i metoda subscribe()

Wywołanie funkcji subscribe() ma jeden efekt uboczny. Jeśli aplikacja internetowa nie ma uprawnień do wyświetlania powiadomień, gdy wywołujesz metodę subscribe(), przeglądarka poprosi o te uprawnienia. Jest to przydatne, jeśli Twój interfejs użytkownika działa z tym procesem, ale jeśli chcesz mieć większą kontrolę (jak większość deweloperów), użyj interfejsu API Notification.requestPermission(), który został omówiony wcześniej w tym dokumencie.

Omówienie PushSubscription

Wywołujesz subscribe(), przekazujesz opcje i otrzymujesz obietnicę, która rozwiązuje się 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 wymagane do wysyłania wiadomości push do tego użytkownika. Jeśli wydrukujesz zawartość za pomocą JSON.stringify(), zobaczysz:

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

endpoint to adres 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

Gdy masz już subskrypcję push, wyślij ją na serwer. To Ty decydujesz, jak wysłać te dane, ale zalecamy użycie metody JSON.stringify(), aby wyodrębnić wszystkie niezbędne dane z obiektu subskrypcji. Możesz też ręcznie uzyskać ten sam wynik, na przykład:

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 tych opcji:

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 otrzymuje 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ółom PushSubscription na serwerze możesz w każdej chwili wysłać wiadomość do użytkownika.

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

Gdy subskrybujesz powiadomienia push, często otrzymujesz PushSubscription.expirationTime typu null. W teorii oznacza to, że subskrypcja nigdy nie wygasa. (DOMHighResTimeStamp wskazuje dokładny czas wygaśnięcia). W praktyce jednak przeglądarki zwykle pozwalają na wygaśnięcie subskrypcji. Może się tak zdarzyć, jeśli przez dłuższy czas nie otrzymasz żadnych powiadomień push lub jeśli przeglądarka wykryje, że użytkownik nie używa aplikacji, która ma zgodę na wyświetlanie powiadomień. Jednym ze sposobów, aby temu zapobiec, jest ponowne zasubskrybowanie użytkownika po każdym otrzymanym powiadomieniu, jak pokazano w tym fragmencie kodu. Wymaga to wysyłania powiadomień na tyle często, aby przeglądarka nie anulowała automatycznie subskrypcji. Należy dokładnie rozważyć zalety i wady uzasadnionych powiadomień w porównaniu z niechcianym spamowaniem użytkownika tylko po to, aby zapobiec wygaśnięciu subskrypcji. Nie należy próbować obchodzić 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 częstych pytań:

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

Nie, przeglądarka wybiera usługę push. Jak wspomniano w tym dokumencie w przypadku 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 używają różnych interfejsów API?

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

Ten wspólny interfejs API, nazywany protokołem Web Push, opisuje żądanie sieciowe, które aplikacja wysyła, aby wywołać wiadomość push.

Jeśli zasubskrybujesz użytkownika na komputerze, czy będzie on zasubskrybowany 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 również od użytkownika przyznania uprawnień na każdym urządzeniu.

Dalsze kroki

Codelabs