Vous pouvez trouver des articles de 2017 à 2018 qui se concentrent sur l'utilisation de moyens relativement basiques pour envoyer et recevoir des messages Web push, par exemple, en utilisant la bibliothèque web-push-libs / web-push . Cette bibliothèque est encore en développement, mais il est beaucoup plus facile de travailler avec les bibliothèques de firebase de nos jours.
Configurer un projet Firebase
Commençons donc par créer un projet sur Firebase. Avec la console Firebase ouverte , un nouveau projet doit être créé. Dans Informations générales-> Paramètres-> Paramètres généraux-> Vos applications, vous devez créer une nouvelle application Web. Cela générera un code d'initialisation de l'application Web sur le frontend:
<!-- 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>
Sur le même onglet de la console Firebase Informations générales-> Paramètres-> Cloud Messaging-> Identifiants pour le projet -> Clé serveur , nous trouvons la clé privée, avec laquelle vous pouvez envoyer des notifications push via le serveur Firebase.
Envoi d'un message push Web
Les développeurs frontaux peuvent envoyer eux-mêmes des messages push Web à l'aide de la commande curl:
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
L'obtention d'une clé de serveur est décrite dans Configuration d'un projet Firebase , et l'obtention d'un jeton d'enregistrement sera décrite dans Obtention d'un jeton d'enregistrement .
données vs charge utile de notification
La charge utile peut être envoyée dans le champ de données ou de notification d'un message push Web. Pour la charge utile de notification, la requête ressemblera à ceci (pour la charge utile de données, voir la requête dans la section Envoi d'un message push ):
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
les données et la charge utile de notification présentent deux différences fondamentales:
- la charge utile de notification a un ensemble de champs strictement défini, les champs supplémentaires seront ignorés, tandis que la charge utile de données envoie tous les champs au frontend sans limitation.
- Si le navigateur Web est en arrière-plan ou si le lien actif contient un site tiers, le push web de la charge utile de notification affiche un message sans passer le contrôle aux gestionnaires d'événements onMessage, tandis que le web push de données utiles transfère toujours le contrôle aux gestionnaires d'événements onMessage, mais pour pour afficher un message, vous devez créer explicitement un objet Notification. Si le navigateur Web est dans un état actif et que notre site est ouvert sur l'onglet actif, le travail avec les données et la charge utile de notification ne diffère pas.
Créer un objet de messagerie
Pour travailler sur le frontend avec des messages push Web, vous devez créer un objet de messagerie:
const messaging = window.firebase.messaging();
Dans ce code,
firebase
il s'agit d'un objet global qui est créé lors du chargement des bibliothèques Firebase et initialisé côté frontal comme décrit dans Configuration d'un projet Firebase . Le projet a été développé dans Vue.js. Par conséquent, la connexion de scripts via un élément de script html ne semblait pas prometteuse. Pour connecter ces scripts, j'ai utilisé la bibliothèque 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
});
Obtention d'un jeton d'enregistrement
Un jeton d'enregistrement est un identifiant qui identifie de manière unique un appareil et un navigateur Web, permettant ainsi à un message push Web d'être envoyé à un appareil spécifique et traité par un navigateur Web spécifique:
Notification.requestPermission()
.then(permission => {
if (permission === "granted") {
messaging
.getToken()
.then(token => {
... //
});
} else {
console.log("Unable to get permission to notify.");
}
});
Dans certaines circonstances, le jeton peut être mis à jour. Et vous devez gérer l'événement de mise à jour du jeton:
messaging.onTokenRefresh(function() {
messaging
.getToken()
.then(function(refreshedToken) {
... //
});
});
Concernant cet événement, j'ai une question - est-ce pertinent. Le fait est qu'avant même de passer à FCM, la procédure de rotation des jetons fonctionnait avec GCM. Cela a été décrit dans la bibliothèque Android et indirectement dans la description du fonctionnement du serveur, où chaque réponse du serveur contenait des jetons canoniques et ils devaient être constamment vérifiés et modifiés (cependant, il s'est avéré que, à part moi, cela était rarement suivi par quiconque). Après être passé à FCM, un concept tel que les jetons canoniques est tombé en désuétude (probablement parce qu'en pratique, ils étaient rarement suivis). À cet égard, les cas où un événement peut survenir ne sont pas entièrement clairs
onTokenRefresh()
.
Événement OnMessage - version simplifiée
Je répondrai immédiatement pourquoi il est simplifié. Nous allons faire au moins deux simplifications. 1) Nous utiliserons la charge utile de notification pour recevoir et afficher des messages si l'application est en arrière-plan sans travail supplémentaire. 2) Oublions que sur les appareils mobiles, le système de sécurité ne permet pas l'exécution du nouvel opérateur Notification ().
Ainsi, comme nous l'avons déjà dit, pour la charge utile de notification, un message push web arrive et s'affiche sans la moindre participation du développeur front-end (bien sûr, après l'envoi du jeton d'enregistrement au serveur). Il reste à déterminer si le navigateur Web est dans un état actif et le site est ouvert sur un onglet actif:
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);
});
Gestion de l'événement de réception d'un message push Web en arrière-plan
Dans cette section, nous allons commencer à travailler avec un technicien de service. Et cela, entre autres, signifie que vous devez configurer le site pour qu'il fonctionne en utilisant le protocole sécurisé https. Et cela complique immédiatement le développement ultérieur. Par conséquent, pour les cas simples, ce qui a déjà été décrit précédemment est suffisant.
Pour travailler avec la bibliothèque Firebase, un fichier nommé
firebase-messaging-sw.js
. Le nom du fichier peut être différent, mais il doit dans tous les cas se trouver dans le répertoire racine en raison du fonctionnement de la protection du navigateur Web (sinon, ce serviteur ne fonctionnera pas pour tout le site).
En règle générale, un gestionnaire d'événements est également placé dans ce fichier
notificationclick
. Vous ne pouvez pratiquement rien trouver de différent de ce code:
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 pour gérer l'événement onMessage avec le technicien de service
Permettez-moi de vous rappeler que dans la section onMessage Event - une version simplifiée, nous avons déjà décrit comment gérer les messages push Web. Mais cette méthode présentait un inconvénient majeur: elle ne fonctionnait pas sur les appareils mobiles en raison des particularités du système de protection du navigateur Web. Pour surmonter cet inconvénient, une option de service worker a été inventée, dans laquelle l'objet Notification est déjà intégré, et il n'a pas besoin d'être créé avec le nouvel opérateur:
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);
});
}
});
});
Bip lors de la réception d'un message push Web
Je dois dire que nous n'avons pratiquement aucun contrôle sur la façon dont les notifications push seront affichées sur divers appareils. Dans certains cas, ce sera un message contextuel, dans d'autres, le push ira immédiatement à la "plaque" du système, et s'il n'y a pas encore de voix, il sera simplement perdu pour le client. Avec un svuk, tout est très difficile. Les spécifications antérieures incluaient un champ sonore, qui était auparavant responsable du son lors de la réception d'un message push Web, mais il n'existe actuellement aucune propriété de ce type. À cet égard, je me suis fixé comme objectif de faire un enregistrement audio du push.
La description parfois rencontrée avec la création d'un élément audio html et l'appel de sa méthode play () ne fonctionne en réalité pas en raison des fonctionnalités de sécurité du navigateur Web (il ne peut être appelé que sur clic d'un utilisateur réel). Mais il y a aussi AudioContext () - nous allons travailler avec:
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);
}
};
Tout va bien, mais nous avons toujours un service worker qui n'a pas d'objet AudioContext (). Rappelons-nous que tous les travailleurs communiquent par messages. Et puis recevoir des événements du technicien de service ressemblera à ceci:
try {
const broadcast = new BroadcastChannel("play");
broadcast.onmessage = play;
} catch (ex) {
console.log(ex) ;
}
Bien sûr, pour que ce code fonctionne, il vous faut 1) Le navigateur est ouvert 2) Le site est ouvert (mais pas forcément sur l'onglet actif). Mais il n'y a pas d'autre moyen.
Au lieu d'une postface
Maintenant, vous pouvez en quelque sorte expirer et dire, c'est tout. Mais ... Tout cela ne fonctionne pas sur safari - et c'est un autre sujet séparé et mal documenté, bien que plusieurs articles puissent être trouvés.
Liens utiles
1) habr.com/ru/post/321924
apapacy@gmail.com
24 août 2020