Sie kennen doch diese kleinen Benachrichtigungsfenster, die in der oberen rechten (Mac) oder unteren rechten (Windows) Ecke erscheinen, wenn zum Beispiel ein neuer Artikel auf unserem Lieblingsblog oder ein neues Video auf YouTube hochgeladen wurde? Das sind Push-Benachrichtigungen.
Ein Teil der Magie dieser Benachrichtigungen ist, dass sie erscheinen können, auch wenn wir uns gerade nicht auf dieser Website befinden, um uns diese Informationen zu übermitteln (nachdem Sie sie genehmigt haben). Auf Mobilgeräten können Sie sie, wo unterstützt, sogar schließen, wenn der Browser geschlossen ist, und trotzdem erhalten.
Artikelserie
- Einrichtung & Firebase (Sie sind hier!)
- Das Back-End

Eine Benachrichtigung besteht aus dem Browserlogo, damit der Benutzer weiß, von welcher Software sie stammt, einem Titel, der URL der Website, von der sie gesendet wurde, einer kurzen Beschreibung und einem benutzerdefinierten Symbol.
Wir werden untersuchen, wie Push-Benachrichtigungen implementiert werden können. Da dies auf Service Workern basiert, schauen Sie sich diese Einstiegspunkte an, wenn Sie damit oder mit der allgemeinen Funktionalität der Push-API nicht vertraut sind.
Was wir erstellen werden

Um unser Benachrichtigungssystem zu testen, erstellen wir eine Seite mit
- einem Abonnement-Button
- einem Formular zum Hinzufügen von Beiträgen
- einer Liste aller zuvor veröffentlichten Beiträge
Ein Repo auf Github mit dem vollständigen Code finden Sie hier und eine Vorschau des Projekts
Und ein Video davon in Aktion
Alle Werkzeuge sammeln
Sie können das Back-End-System frei wählen, das am besten zu Ihnen passt. Ich habe mich für Firebase entschieden, da es eine spezielle API bietet, die die Implementierung eines Push-Benachrichtigungsdienstes relativ einfach macht.
Wir brauchen
- einen Service Worker (und damit HTTPS)
- ein Manifest
- Firebase Realtime Database zum Speichern unserer Beiträge
- Firebase Cloud Messaging, das uns „ermöglicht, Nachrichten zuverlässig und kostenlos zu liefern“
- Firebase Cloud Functions, das Änderungen in unserer Datenbank überwacht und die Benachrichtigungen sendet
In diesem Teil konzentrieren wir uns nur auf das Front-End, einschließlich des Service Workers und des Manifests. Um Firebase nutzen zu können, müssen Sie sich jedoch auch registrieren und ein neues Projekt erstellen.
Implementierung der Abonnementlogik
HTML
Wir haben einen Button zum Abonnieren, der aktiviert wird, if 'serviceWorker' in navigator. Darunter ein einfaches Formular und eine Liste von Beiträgen.
<button id="push-button" disabled>Subscribe</button>
<form action="#">
<input id="input-title">
<label for="input-title">Post Title</label>
<button type="submit" id="add-post">Add Post</button>
</form>
<ul id="list"></ul>
Firebase implementieren
Um Firebase nutzen zu können, müssen wir einige Skripte implementieren.
<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.3/firebase-messaging.js"></script>
Nun können wir Firebase mit den Anmeldeinformationen unter Projekteinstellungen → Allgemein initialisieren. Die Sender-ID finden Sie unter Projekteinstellungen → Cloud Messaging. Die Einstellungen sind hinter dem Zahnradsymbol in der oberen linken Ecke verborgen.
firebase.initializeApp({
apiKey: '<API KEY>',
authDomain: '<PROJECT ID>.firebaseapp.com',
databaseURL: 'https://<PROJECT ID>.firebaseio.com',
projectId: '<PROJECT ID>',
storageBucket: '<PROJECT ID>.appspot.com',
messagingSenderId: '<SENDER ID>'
})
Service Worker Registrierung
Firebase bietet eine eigene Service-Worker-Einrichtung, indem eine Datei namens `firebase-messaging-sw.js` erstellt wird, die alle Funktionen zur Verarbeitung von Push-Benachrichtigungen enthält. Normalerweise muss Ihr Service Worker jedoch mehr tun. Mit der Methode useServiceWorker können wir Firebase mitteilen, auch unsere eigene Datei `service-worker.js` zu verwenden.
Jetzt können wir eine Variable userToken und eine Variable isSubscribed erstellen, die später verwendet werden.
const messaging = firebase.messaging(),
database = firebase.database(),
pushBtn = document.getElementById('push-button')
let userToken = null,
isSubscribed = false
window.addEventListener('load', () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
messaging.useServiceWorker(registration)
initializePush()
})
.catch(err => console.log('Service Worker Error', err))
} else {
pushBtn.textContent = 'Push not supported.'
}
})
Push-Setup initialisieren
Beachten Sie die Funktion initializePush() nach der Service Worker-Registrierung. Sie prüft, ob der aktuelle Benutzer bereits abonniert ist, indem sie nach einem Token in localStorage sucht. Wenn ein Token vorhanden ist, ändert sie den Button-Text und speichert den Token in einer Variable.
function initializePush() {
userToken = localStorage.getItem('pushToken')
isSubscribed = userToken !== null
updateBtn()
pushBtn.addEventListener('click', () => {
pushBtn.disabled = true
if (isSubscribed) return unsubscribeUser()
return subscribeUser()
})
}
Hier behandeln wir auch das Klickereignis auf den Abonnement-Button. Wir deaktivieren den Button bei einem Klick, um mehrfache Auslösungen zu vermeiden.
Button für Abonnement aktualisieren
Um den aktuellen Abonnementstatus widerzuspiegeln, müssen wir den Text und den Stil des Buttons anpassen. Wir können auch prüfen, ob der Benutzer Push-Benachrichtigungen beim Auffordern nicht zugelassen hat.
function updateBtn() {
if (Notification.permission === 'denied') {
pushBtn.textContent = 'Subscription blocked'
return
}
pushBtn.textContent = isSubscribed ? 'Unsubscribe' : 'Subscribe'
pushBtn.disabled = false
}
Benutzer abonnieren
Nehmen wir an, der Benutzer besucht uns zum ersten Mal in einem modernen Browser, ist also noch nicht abonniert. Außerdem werden Service Worker und Push API unterstützt. Wenn er auf den Button klickt, wird die Funktion subscribeUser() ausgelöst.
function subscribeUser() {
messaging.requestPermission()
.then(() => messaging.getToken())
.then(token => {
updateSubscriptionOnServer(token)
isSubscribed = true
userToken = token
localStorage.setItem('pushToken', token)
updateBtn()
})
.catch(err => console.log('Denied', err))
}
Hier bitten wir um Erlaubnis, Push-Benachrichtigungen an den Benutzer zu senden, indem wir messaging.requestPermission() aufrufen.

Wenn der Benutzer diese Anfrage blockiert, wird der Button so angepasst, wie wir es in der Funktion updateBtn() implementiert haben. Wenn der Benutzer diese Anfrage zulässt, wird ein neuer Token generiert, in einer Variablen sowie in localStorage gespeichert. Der Token wird von updateSubscriptionOnServer() in unserer Datenbank gespeichert.
Abonnement in unserer Datenbank speichern
Wenn der Benutzer bereits abonniert war, zielen wir auf den richtigen Datenbankverweis, wo wir die Token gespeichert haben (in diesem Fall device_ids), suchen nach dem Token, den der Benutzer zuvor bereitgestellt hat, und entfernen ihn.
Andernfalls möchten wir den Token speichern. Mit .once('value') erhalten wir die Schlüsselwerte und können prüfen, ob der Token bereits vorhanden ist. Dies dient als zweite Schutzmaßnahme zur Suche in localStorage in initializePush(), da der Token aus verschiedenen Gründen von dort gelöscht werden könnte. Wir möchten nicht, dass der Benutzer mehrere Benachrichtigungen mit demselben Inhalt erhält.
function updateSubscriptionOnServer(token) {
if (isSubscribed) {
return database.ref('device_ids')
.equalTo(token)
.on('child_added', snapshot => snapshot.ref.remove())
}
database.ref('device_ids').once('value')
.then(snapshots => {
let deviceExists = false
snapshots.forEach(childSnapshot => {
if (childSnapshot.val() === token) {
deviceExists = true
return console.log('Device already registered.');
}
})
if (!deviceExists) {
console.log('Device subscribed');
return database.ref('device_ids').push(token)
}
})
}
Benutzer abbestellen
Wenn der Benutzer nach erneutem Abonnieren auf den Button klickt, wird sein Token gelöscht. Wir setzen unsere Variablen userToken und isSubscribed zurück, entfernen den Token aus localStorage und aktualisieren unseren Button erneut.
function unsubscribeUser() {
messaging.deleteToken(userToken)
.then(() => {
updateSubscriptionOnServer(userToken)
isSubscribed = false
userToken = null
localStorage.removeItem('pushToken')
updateBtn()
})
.catch(err => console.log('Error unsubscribing', err))
}
Damit der Service Worker weiß, dass wir Firebase verwenden, importieren wir die Skripte zuerst in `service-worker.js`.
importScripts('https://www.gstatic.com/firebasejs/4.1.3/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/4.1.3/firebase-database.js')
importScripts('https://www.gstatic.com/firebasejs/4.1.3/firebase-messaging.js')
Wir müssen Firebase erneut initialisieren, da der Service Worker nicht auf die Daten in unserer `main.js`-Datei zugreifen kann.
firebase.initializeApp({
apiKey: "<API KEY>",
authDomain: "<PROJECT ID>.firebaseapp.com",
databaseURL: "https://<PROJECT ID>.firebaseio.com",
projectId: "<PROJECT ID>",
storageBucket: "<PROJECT ID>.appspot.com",
messagingSenderId: "<SENDER ID>"
})
Darunter fügen wir alle Ereignisse rund um die Behandlung des Benachrichtigungsfensters hinzu. In diesem Beispiel schließen wir die Benachrichtigung und öffnen eine Website, nachdem darauf geklickt wurde.
self.addEventListener('notificationclick', event => {
event.notification.close()
event.waitUntil(
self.clients.openWindow('https://artofmyself.com')
)
})
Ein weiteres Beispiel wäre die Synchronisierung von Daten im Hintergrund. Lesen Sie Googles Artikel dazu.
Nachrichten anzeigen, wenn auf der Website
Wenn wir Benachrichtigungen über neue Beiträge abonniert haben, aber gleichzeitig den Blog besuchen, wenn ein neuer Beitrag veröffentlicht wird, erhalten wir keine Benachrichtigung.
Eine Möglichkeit, dies zu lösen, ist die Anzeige einer anderen Art von Nachricht auf der Website selbst, wie z. B. eine kleine Snackbar am unteren Rand.

Um die Nutzlast der Nachricht abzufangen, rufen wir die Methode onMessage von Firebase Messaging auf.
Das Styling in diesem Beispiel verwendet Material Design Lite.
<div id="snackbar" class="mdl-js-snackbar mdl-snackbar">
<div class="mdl-snackbar__text"></div>
<button class="mdl-snackbar__action" type="button"></button>
</div>
import 'material-design-lite'
messaging.onMessage(payload => {
const snackbarContainer = document.querySelector('#snackbar')
let data = {
message: payload.notification.title,
timeout: 5000,
actionHandler() {
location.reload()
},
actionText: 'Reload'
}
snackbarContainer.MaterialSnackbar.showSnackbar(data)
})
Manifest hinzufügen
Der letzte Schritt für diesen Teil der Serie ist das Hinzufügen der Google Cloud Messaging Sender ID zur Datei `manifest.json`. Diese ID stellt sicher, dass Firebase Nachrichten an unsere App senden darf. Wenn Sie noch kein Manifest haben, erstellen Sie eines und fügen Sie Folgendes hinzu. Ändern Sie den Wert nicht.
{
"gcm_sender_id": "103953800507"
}
Jetzt sind wir im Front-End fertig. Übrig bleibt die Erstellung unserer eigentlichen Datenbank und der Funktionen zur Überwachung von Datenbankänderungen im nächsten Artikel.
Artikelserie
- Einrichtung & Firebase (Sie sind hier!)
- Das Back-End
Nur aus Neugier, im Abschnitt „Nachrichten anzeigen, wenn auf der Website“, ist dieser Ansatz auch in Safari und Edge machbar? Können wir dies verwenden, um eine „Messaging-Erfahrung“ in einer Web-App zu schaffen? Die meisten Tutorials, die ich gelesen habe, basieren auf den Push-Benachrichtigungsfunktionen von Chrome, aber was können wir tun, um Browsermeldungen für andere Browser bereitzustellen?
Nein. Siehe caniuse für „push API“.
Push-Benachrichtigungen sind nicht spezifisch für Chrome. Sie funktionieren auch in Firefox, Samsung Internet und Opera.
Der Browser muss zuerst Service Worker unterstützen, was Edge und Safari nur in ihren Vorschauen tun.
Safari hat auch eine eigene, nicht standardmäßige Implementierung einer Push-API. Diese könnten Sie verwenden.
Das ist es, was ich gesucht habe. Wann kommt der zweite Teil?
Großartig, aber gibt es eine Alternative zu Firebase? Oder ist eine selbst gehostete Lösung möglich?
Ja, Sie können die Daten (Token) an Ihr Backend senden und in einer eigenen Datenbank speichern.
Hallo Freund. Ich habe das Github-Repo geklont, aber es unterscheidet sich stark vom hier gezeigten Beispiel. Ich möchte wissen, wie ich es zum Laufen bringe. Wann posten Sie den zweiten Teil?
Hallo Jonathan,
wie unterscheidet sich das Repo von den Beispielen hier?
Der zweite Teil war bereits online, als Sie das geschrieben haben.