un file JavaScript che registra il service worker, /js/register-service-worker.js
un file JavaScript che il codice del service worker, /service-worker-push.js
Pagina HTML
La pagina HTML non ha particolari requisiti, dovrà solo richiamare il file /js/register-service-worker.js, mentre il contenuto HTML/JavaScript dipenderà dalla specifica applicazione
Il file /js/register-service-worker.js è quello che si occupa di verificare se il browser ha il supporto per i service worker e, se si, lo istanzia immediatamente al caricamento della pagina
JavaScript: /js/register-service-worker.js
// Register a Service Worker.
console.log('sgart:rsw:Registrazione service worker');
navigator.serviceWorker.register('service-worker-push.js');
let pushRegistration = null;
// quando la registrazione è andata a buon fine
navigator.serviceWorker.ready
.then(function (registration) {
console.log('sgart:rsw:ready');
// salvo la registrazione per usarla successivamente
pushRegistration = registration;
// recupero la sottoscrizione.
return registration.pushManager.getSubscription()
.then(async function (subscription) {
console.log('sgart:rsw:getSubscription');
if (subscription) {
// se la subscription esisteva, la ritorno
return subscription;
}
// recupero la chiave pubblica dal server (settings.json)
const response = await fetch('/api/push/public-key');
const responseJson = await response.json();
const convertedVapidKey = urlBase64ToUint8Array(responseJson.publicKey);
// Effettuo la sottoscrizione
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
})
.then(async function (subscription) {
// uso le Fetch API per salvare su database i dati della subscription
// le informazioni serviranno poi per inviare le notifiche
console.log('sgart:rsw:saving push registration');
const response = await fetch('/api/push/registration', {
method: 'post',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify(subscription)
});
if (response.ok) {
console.log('sgart:rsw:saved push registration');
}
})
.catch(function (error) {
console.error('sgart:rsw:saving push registration', error);
});
a questo si aggiunge la funzione urlBase64ToUint8Array
JavaScript: urlBase64ToUint8Array(base64String)
// This function is needed because Chrome doesn't accept a base64 encoded string
// as value for applicationServerKey in pushManager.subscribe yet
// https://bugs.chromium.org/p/chromium/issues/detail?id=802280
function urlBase64ToUint8Array(base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4);
var base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
var rawData = window.atob(base64);
var outputArray = new Uint8Array(rawData.length);
for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
sul browser comparirà un popup con la richiesta di confermare la sottoscrizionePopup di conferma
Service Worker
In ultimo c'è il service worker, ovvero quel servizio JavaScript che rimane sempre attivo, anche quando il browser è chiuso, che si occupa di ricevere il messaggio e formattarlo per la visualizzazione.
In pratica gestisce l'evento push che prende il messaggio (event.data.json()), costruisce l'oggetto che rappresenta la notifica (options) e invoca il metodo self.registration.showNotification che visualizza la notifica sul client:
JavaScript: service-worker-push.js
self.addEventListener('push', function (event) {
console.log(`sgart:swp:push event`, event);
if (!(self.Notification && self.Notification.permission === 'granted')) {
console.warn(`sgart:swp:push event NOT supported/grated`);
return;
}
var data = {};
if (event.data) {
data = event.data.json();
}
// formatto la notifica
var title = data.title || "Sgart Test Push";
var options = {
body: `${data.message}\nsent: ${data.dateSent}\nsubscriptionId: ${data.subscriptionId}` || "message empty",
//tag: 'sgart-push-demo',
icon: data.icon || "/images/new-notification.png"
};
event.waitUntil(
// visualizzo la notifica sul dispositivo client
self.registration.showNotification(title, options)
);
});
Lato Server
La parte server, realizzata in NodeJS, espone 3 APIJSON
GET /api/push/public-key: ritorna la chiave pubblica presente in settings.json
POST /api/push/registration: aggiunge una sottoscrizione al databasesqlite
DELETE /api/push/registration: rimuove una sottoscrizione dal database
Esiste anche il metodo generateRequestDetails identico a sendNotification solo che non invia nessuna notifica, ritorna solo le informazioni della richesta, utile per debug.
Debug Service Worker
In Chrome è possibile vedere i service worker registrati aprendo la developer toolbar (F12) nella scheda ApplicationElenco service workered è possibile fare debug del codice dalla scheda ourceSource debug service worker
Se avendo aperta la developer toolbar, il codice del service worker non si aggiorna, può essere necessario deregistrarlo (unregister) dalla scheda applicazioni e fare refresh della pagina.