Avant-propos
Pour tenter de trouver un bon article sur la configuration des notifications dans le navigateur, je n'ai reçu que des articles décrivant principalement l'utilisation en conjonction avec Firebase, mais cette option ne me convenait pas particulièrement.
Dans cet article, les principes de fonctionnement et les subtilités des notifications Push ne seront pas « brouillés », uniquement le code, uniquement le hardcore.
Notes IMPORTANTES
Les notifications push ne fonctionnent qu'avec HTTPS .
D'ailleurs, en plus du HTTPS, un certificat SSL valide doit être présent, Let's Encrypt fera l'affaire.
Localhost est parfait pour le développement. Il ne devrait pas y avoir de problèmes, mais si cela se produit, cet article vous aidera à les résoudre.
Qu'il y ait du code
Autorisation (VAPID)
Tout d'abord, cela vaut la peine d'installer la bibliothèque WebPush dans votre projet php :
$ composer require minishlink/web-push
Ensuite, pour autoriser votre serveur avec un navigateur (VAPID), vous devez générer des clés ssh publiques et privées. Ces clés seront nécessaires à la fois sur le serveur et sur le client (sauf que seule la publique est nécessaire sur le client) .
Pour générer une clé publique et privée codée en Base64 non compressée, entrez ce qui suit dans votre bash Linux :
$ openssl ecparam -genkey -name prime256v1 -out private_key.pem
$ openssl ec -in private_key.pem -pubout -outform DER|tail -c 65|base64|tr -d '=' |tr '/+' '_-' >> public_key.txt
$ openssl ec -in private_key.pem -outform DER|tail -c +8|head -c 32|base64|tr -d '=' |tr '/+' '_-' >> private_key.txt
De plus, l'auteur de la bibliothèque fournit la génération de clés vapid en utilisant la méthode intégrée :
$vapidKeysInBase64 = VAPID::createVapidKeys();
Abonnement
Étape 1 (JS)
ServiceWorker, PushManager, showNotification :
app.js
function checkNotificationSupported() {
return new Promise((fulfilled, reject) => {
if (!('serviceWorker' in navigator)) {
reject(new Error('Service workers are not supported by this browser'));
return;
}
if (!('PushManager' in window)) {
reject(new Error('Push notifications are not supported by this browser'));
return;
}
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
reject(new Error('Notifications are not supported by this browser'));
return;
}
fulfilled();
})
}
sw.js :
app.js
navigator.serviceWorker.register('sw.js').then(() => {
console.log('[SW] Service worker has been registered');
}, e => {
console.error('[SW] Service worker registration failed', e);
}
);
:
app.js
function checkNotificationPermission() {
return new Promise((fulfilled, reject) => {
if (Notification.permission === 'denied') {
return reject(new Error('Push messages are blocked.'));
}
if (Notification.permission === 'granted') {
return fulfilled();
}
if (Notification.permission === 'default') {
return Notification.requestPermission().then(result => {
if (result !== 'granted') {
reject(new Error('Bad permission result'));
} else {
fulfilled();
}
});
}
return reject(new Error('Unknown permission'));
});
}
ssh :
<script>
window.applicationServerKey = '<?= $yourPublicKeyFromServer ?>'
</script>
, . 10 .
app.js
document.addEventListener('DOMContentLoaded', documentLoadHandler);
function documentLoadHandler() {
checkNotificationSupported()
.then(() => {
setTimeout(() => {
serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(window.applicationServerKey),
})
.then(successSubscriptionHandler, errorSubscriptionHandler)
}, 10000);
},
console.error
);
}
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function errorSubscriptionHandler(err) {
if (Notification.permission === 'denied') {
console.warn('Notifications are denied by the user.');
} else {
console.error('Impossible to subscribe to push notifications', err);
}
}
successSubscriptionHandler
.
app.js
function successSubscriptionHandler(subscriptionData) {
const key = subscription.getKey('p256dh');
const token = subscription.getKey('auth');
const contentEncoding = (PushManager.supportedContentEncodings || ['aesgcm'])[0];
const body = new FormData();
body.set('endpoint', subscription.endpoint);
body.set('publicKey', key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : null);
body.set('authToken', token ? btoa(String.fromCharCode.apply(null, new Uint8Array(token))) : null);
body.set('contentEncoding', contentEncoding);
return fetch('src/push_subscription.php', {
method,
body,
}).then(() => subscription);
}
Post Message API
self.addEventListener('push', function (event) {
if (!(self.Notification && self.Notification.permission === 'granted')) {
return;
}
const sendNotification = body => {
const title = " ";
return self.registration.showNotification(title, {
body,
});
};
if (event.data) {
const message = event.data.text();
event.waitUntil(sendNotification(message));
}
});
2 (PHP)
php 7+
subscribeUserToPushNotifications ,
subscribeUserToPushNotifications.php
<?php
$subscription = $_POST;
if (!isset($subscription['endpoint'])) {
echo 'Error: not a subscription';
return;
}
// save subscription from => $subscription
( ), .
, :
pushNotificationToClient.php
<?php
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;
$subscription = Subscription::create($subscriptionData);
VAPID :
pushNotificationToClient.php
<?php
$auth = array(
'VAPID' => array(
'subject' => 'https://your-project-domain.com',
'publicKey' => file_get_contents(__DIR__ . '/your_project/keys/public_key.txt'),
'privateKey' => file_get_contents(__DIR__ . '/your_project/keys/private_key.txt'),
)
);
, WebPush:
pushNotificationToClient.php
<?php
$webPush = new WebPush($auth);
! Push
<?php
$report = $webPush->sendOneNotification(
$subscription,
" , sw.js"
);
Note importante
Pour envoyer des notifications par itération, vous devez utiliser une fonction avec les mêmes paramètres que dans la fonction ci-dessus :
$webPush->queueNotification
Sources utiles
À propos de la technologie push
À propos de WebPush de Khabrovchanin
Bibliothèque WebPush
Un exemple d'utilisation d'un développeur de bibliothèque