Sie finden Artikel aus den Jahren 2017 ... 2018, die sich auf die Verwendung relativ einfacher Mittel zum Senden und Empfangen von Web-Push-Nachrichten konzentrieren, z. B. mithilfe der Bibliothek web-push-libs / web-push . Diese Bibliothek befindet sich noch in der Entwicklung, es ist jedoch heutzutage viel einfacher, mit Bibliotheken aus Firebase zu arbeiten.
Einrichten eines Firebase-Projekts
Beginnen wir also damit, ein Projekt auf Firebase zu erstellen. Bei geöffneter Firebase-Konsole muss ein neues Projekt erstellt werden. Unter Allgemeine Informationen-> Einstellungen-> Allgemeine Einstellungen-> Ihre Anwendungen müssen Sie eine neue Webanwendung erstellen. Dadurch wird auf der Frontend-Seite ein Initialisierungscode für Webanwendungen generiert:
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.19.0/firebase-app.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.19.0/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
Auf demselben Registerkarte der Feuerbasis Konsole Allgemein Information-> Einstellungen-> Cloud - Messaging-> Credentials für das Projekt -> Server Schlüssel, wir die privaten Schlüssel finden, mit denen Sie Push - Benachrichtigungen über den Server Feuerbasis senden.
Senden einer Web-Push-Nachricht
Front-End-Entwickler können Web-Push-Nachrichten mit dem Befehl curl selbst senden:
curl -X POST -H "Authorization: key=< >" -H "Content-Type: application/json" -d '{
"data": {
"title": "FCM Message",
"body": "This is an <i>FCM Message</i>",
"icon": "/static/plus.png",
"sound": "/static/push.mp3",
"click_action": "https://google.com",
},
"to": "< >"
}' https://fcm.googleapis.com/fcm/send
Das Abrufen eines Serverschlüssels wird im Abschnitt Einrichten eines Firebase-Projekts beschrieben. Das Abrufen eines Registrierungstokens wird im Abschnitt Abrufen eines Registrierungstokens beschrieben .
Daten vs Benachrichtigungsnutzlast
Die Nutzdaten können im Daten- oder Benachrichtigungsfeld einer Web-Push-Nachricht gesendet werden. Für Benachrichtigungsnutzdaten sieht die Anforderung folgendermaßen aus (für Datennutzdaten siehe die Anforderung im Abschnitt Senden einer Push-Nachricht ):
curl -X POST -H "Authorization: key=< >" -H "Content-Type: application/json" -d '{
"notification": {
"title": "FCM Message",
"body": "This is an <i>FCM Message</i>",
"icon": "/static/plus.png",
"click_action": "https://google.com",
},
"to": "< >"
}' https://fcm.googleapis.com/fcm/send
Daten- und Benachrichtigungsnutzdaten weisen zwei grundlegende Unterschiede auf:
- Benachrichtigungsnutzdaten haben einen genau definierten Satz von Feldern, zusätzliche Felder werden ignoriert, während Datennutzdaten alle Felder ohne Einschränkung an das Frontend senden.
- Befindet sich der Webbrowser im Hintergrund oder enthält der aktive Link eine Website eines Drittanbieters, zeigt der Benachrichtigungs-Payload-Web-Push eine Nachricht an, ohne die Kontrolle an die onMessage-Ereignishandler zu übertragen, während der Datennutzlast-Web-Push die Kontrolle immer an die onMessage-Ereignishandler überträgt, jedoch für Um eine Nachricht anzuzeigen, müssen Sie explizit ein Benachrichtigungsobjekt erstellen. Wenn sich der Webbrowser in einem aktiven Zustand befindet und unsere Website auf der aktiven Registerkarte geöffnet ist, unterscheidet sich die Arbeit mit Daten und Benachrichtigungsnutzdaten nicht.
Erstellen eines Messaging-Objekts
Um im Frontend mit Web-Push-Nachrichten zu arbeiten, müssen Sie ein Messaging-Objekt erstellen:
const messaging = window.firebase.messaging();
In diesem Code ist
firebasedies ein globales Objekt, das beim Laden der Firebase-Bibliotheken erstellt und auf der Frontend-Seite initialisiert wird, wie unter Einrichten eines Firebase-Projekts beschrieben . Das Projekt wurde in Vue.js entwickelt. Daher sah das Verbinden von Skripten über ein HTML-Skriptelement nicht vielversprechend aus. Um diese Skripte zu verbinden, habe ich die Bibliothek verwendet vue-plugin-load-script:
import Vue from "vue";
import LoadScript from "vue-plugin-load-script";
Vue.use(LoadScript);
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
Promise.resolve()
.then(() =>
Vue.loadScript(
"https://www.gstatic.com/firebasejs/7.14.0/firebase-app.js"
)
)
.then(() =>
Vue.loadScript(
"https://www.gstatic.com/firebasejs/7.14.0/firebase-messaging.js"
)
)
.then(() =>
Vue.loadScript(
"https://www.gstatic.com/firebasejs/7.14.0/firebase-analytics.js"
)
)
.then(() => {
window.firebase.initializeApp(firebaseConfig);
const messaging = window.firebase.messaging();
... // messaging
});
Erhalten eines Registrierungstokens
Ein Registrierungstoken ist eine Kennung, die ein Gerät und einen Webbrowser eindeutig identifiziert, sodass eine Web-Push-Nachricht an ein bestimmtes Gerät gesendet und von einem bestimmten Webbrowser verarbeitet werden kann:
Notification.requestPermission()
.then(permission => {
if (permission === "granted") {
messaging
.getToken()
.then(token => {
... //
});
} else {
console.log("Unable to get permission to notify.");
}
});
Unter bestimmten Umständen kann das Token aktualisiert werden. Und Sie müssen das Token-Update-Ereignis behandeln:
messaging.onTokenRefresh(function() {
messaging
.getToken()
.then(function(refreshedToken) {
... //
});
});
Zu diesem Ereignis habe ich eine Frage - ist es relevant? Tatsache ist, dass das Token-Rotationsverfahren bereits vor dem Wechsel zu FCM mit GCM funktioniert hat. Dies wurde in der Android-Bibliothek und indirekt in der Beschreibung des Serverbetriebs beschrieben, wo jede Serverantwort kanonische Token enthielt und diese ständig überprüft und geändert werden mussten (wie sich jedoch herausstellte, wurde sie von niemandem außer mir selten befolgt). Nach dem Wechsel zu FCM wurde ein Konzept wie kanonische Token nicht mehr verwendet (höchstwahrscheinlich, weil sie in der Praxis selten verfolgt wurden). In dieser Hinsicht sind die Fälle, in denen ein Ereignis eintreten kann, nicht ganz klar
onTokenRefresh().
OnMessage-Ereignis - vereinfachte Version
Ich werde sofort antworten, warum es vereinfacht ist. Wir werden mindestens zwei Vereinfachungen vornehmen. 1) Wir verwenden Benachrichtigungsnutzdaten, um Nachrichten zu empfangen und anzuzeigen, wenn sich die Anwendung ohne zusätzliche Arbeit im Hintergrund befindet. 2) Vergessen Sie, dass das Sicherheitssystem auf Mobilgeräten nicht zulässt, dass der neue Notification () -Operator ausgeführt wird.
Wie bereits erwähnt, wird für die Nutzdaten von Benachrichtigungen eine Web-Push-Nachricht angezeigt, die ohne die geringste Beteiligung des Front-End-Entwicklers angezeigt wird (natürlich nach dem Senden des Registrierungstokens an den Server). Es bleibt abzuwarten, ob sich der Webbrowser in einem aktiven Zustand befindet und die Site auf einer aktiven Registerkarte geöffnet ist:
messaging.onMessage(function(payload) {
const data = { ...payload.notification, ...payload.data };
const notificationTitle = data.title;
const notificationOptions = {
body: data.body,
icon: data.icon,
image: data.image,
click_action: data.click_action,
requireInteraction: true,
data
};
new Notification(payload.notification.title, payload.notification);
});
Behandlung des Ereignisses des Empfangs einer Web-Push-Nachricht im Hintergrund
In diesem Abschnitt beginnen wir mit einem Servicemitarbeiter zu arbeiten. Dies bedeutet unter anderem, dass Sie die Site so konfigurieren müssen, dass sie mit dem sicheren https-Protokoll funktioniert. Und das erschwert sofort die Weiterentwicklung. Für einfache Fälle ist daher ausreichend, was bereits zuvor beschrieben wurde.
Um mit der Firebase-Bibliothek zu arbeiten, wird eine Datei mit dem Namen verwendet
firebase-messaging-sw.js. Der Name der Datei kann unterschiedlich sein, muss sich jedoch aufgrund der Funktionsweise des Webbrowser-Schutzes auf jeden Fall im Stammverzeichnis befinden (andernfalls funktioniert dieser Serivce Worker nicht für die gesamte Site).
In der Regel wird in dieser Datei auch ein Event-Handler abgelegt
notificationclick. Sie können kaum etwas anderes als diesen Code finden:
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
importScripts("https://www.gstatic.com/firebasejs/7.17.2/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/7.17.2/firebase-messaging.js");
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
const data = { ...payload.notification, ...payload.data };
const notificationTitle = data.title;
const notificationOptions = {
body: data.body,
icon: data.icon,
image: data.image,
requireInteraction: true,
click_action: data.click_action,
data
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
self.addEventListener("notificationclick", function(event) {
const target = event.notification.data.click_action;
event.notification.close();
event.waitUntil(
clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(function(clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
console.log(client.url, client.focus);
if (client.url === target && "focus" in client) {
return client.focus();
}
}
return clients.openWindow(target);
})
);
});
Option zur Behandlung des onMessage-Ereignisses mit dem Servicemitarbeiter
Ich möchte Sie daran erinnern, dass wir im Abschnitt über Nachrichtenereignis - eine vereinfachte Version - bereits beschrieben haben, wie mit Web-Push-Nachrichten umgegangen wird . Diese Methode hatte jedoch einen wesentlichen Nachteil: Sie funktionierte auf Mobilgeräten aufgrund der Besonderheiten des Webbrowser-Schutzsystems nicht. Um diesen Nachteil zu überwinden, wurde eine Service-Worker-Option erfunden, in die das Benachrichtigungsobjekt bereits eingebettet ist und die nicht mit dem neuen Operator erstellt werden muss:
messaging.onMessage(function(payload) {
play();
navigator.serviceWorker.register("/firebase-messaging-sw.js");
Notification.requestPermission(function(result) {
if (result === "granted") {
navigator.serviceWorker.ready
.then(function(registration) {
const data = { ...payload.notification, ...payload.data };
const notificationTitle = data.title;
const notificationOptions = {
body: data.body,
icon: data.icon,
image: data.image,
click_action: data.click_action,
requireInteraction: true,
data
};
return registration.showNotification(
notificationTitle,
notificationOptions
);
})
.catch(function(error) {
console.log("ServiceWorker registration failed", error);
});
}
});
});
Signalton beim Empfang einer Web-Push-Nachricht
Ich muss sagen, dass wir praktisch keine Kontrolle darüber haben, wie Push-Benachrichtigungen auf verschiedenen Geräten angezeigt werden. In einigen Fällen handelt es sich um eine Popup-Nachricht, in anderen Fällen fällt der Push sofort in die Systemplatte, und wenn noch keine Sprachausgabe erfolgt, geht er einfach für den Client verloren. Mit einem Svuk ist alles sehr schwierig. Frühere Spezifikationen enthielten ein Soundfeld, das zuvor beim Empfang einer Web-Push-Nachricht für den Sound verantwortlich war. Derzeit gibt es jedoch keine solche Eigenschaft. In dieser Hinsicht habe ich mir das Ziel gesetzt, eine Audioaufnahme des Pushs zu machen.
Die manchmal auftretende Beschreibung beim Erstellen eines HTML-Audioelements und beim Aufrufen seiner play () -Methode funktioniert in der Realität aufgrund der Sicherheitsfunktionen des Webbrowsers nicht (sie kann nur auf einen Klick eines echten Benutzers aufgerufen werden). Es gibt aber auch AudioContext () - wir werden damit arbeiten:
const play = () => {
try {
const context = new AudioContext();
window
.fetch(soundUrl)
.then(response => response.arrayBuffer())
.then(arrayBuffer => context.decodeAudioData(arrayBuffer))
.then(audioBuffer => {
const source = context.createBufferSource();
source.buffer = audioBuffer;
source.connect(context.destination);
source.start();
});
} catch (ex) {
console.log(ex);
}
};
Alles ist in Ordnung, aber wir haben immer noch einen Servicemitarbeiter, der kein AudioContext () -Objekt hat. Denken wir daran, dass alle Mitarbeiter über Nachrichten kommunizieren. Und dann sieht das Empfangen von Ereignissen vom Servicemitarbeiter folgendermaßen aus:
try {
const broadcast = new BroadcastChannel("play");
broadcast.onmessage = play;
} catch (ex) {
console.log(ex) ;
}
Damit dieser Code funktioniert, benötigen Sie natürlich 1) den Browser ist geöffnet 2) die Site ist geöffnet (obwohl nicht unbedingt auf der aktiven Registerkarte). Aber es gibt keinen anderen Weg.
Anstelle eines Nachwortes
Jetzt kannst du irgendwie ausatmen und sagen, das war's. Aber ... All dies funktioniert nicht auf Safari - und dies ist ein weiteres separates und schlecht dokumentiertes Thema, obwohl mehrere Artikel zu finden sind.
Nützliche Links
1) habr.com/ru/post/321924
apapacy@gmail.com
24. August 2020