Notifiche push sul Web aperto

Matt Gaunt

Se chiedi a un gruppo di sviluppatori quali funzionalità dei dispositivi mobili mancano sul Web, le notifiche push sono sempre in cima all'elenco.

Le notifiche push consentono agli utenti di attivare gli aggiornamenti tempestivi dai loro siti preferiti e di coinvolgerli nuovamente con contenuti personalizzati e coinvolgenti.

A partire dalla versione 42 di Chrome, l'API Push e l'API Notification sono disponibili per gli sviluppatori.

L'API Push in Chrome si basa su diverse tecnologie, inclusi i file manifest delle app web e i service worker. In questo post esamineremo ciascuna di queste tecnologie, ma solo il minimo indispensabile per rendere operativi i messaggi push. Per comprendere meglio alcune delle altre funzionalità dei manifest e delle funzionalità offline dei service worker, dai un'occhiata ai link qui sopra.

Vedremo anche cosa sarà aggiunto all'API nelle future versioni di Chrome e infine parleremo delle domande frequenti.

Implementazione della messaggistica push per Chrome

In questa sezione vengono descritti tutti i passaggi da completare per supportare i messaggi push nella tua applicazione web.

Registra un service worker

La necessità di avere un service worker per implementare i messaggi push per il web è una dipendenza. Il motivo è che, quando viene ricevuto un messaggio push, il browser può avviare un service worker, che viene eseguito in background senza che la pagina sia aperta, e inviare un evento in modo che tu possa decidere come gestire il messaggio push.

Di seguito è riportato un esempio di come registrare un service worker nell'app web. Al termine della registrazione, chiamiamo initialiseState(), di cui parleremo a breve.

var isPushEnabled = false;

…

window.addEventListener('load', function() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.addEventListener('click', function() {
    if (isPushEnabled) {
        unsubscribe();
    } else {
        subscribe();
    }
    });

    // Check that service workers are supported, if so, progressively
    // enhance and add push messaging support, otherwise continue without it.
    if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
    .then(initialiseState);
    } else {
    console.warn('Service workers aren\'t supported in this browser.');
    }
});

Il gestore dei clic sui pulsanti sottoscrive o annulla l'iscrizione dell'utente per i messaggi push. isPushEnabled è una variabile globale che monitora semplicemente se i messaggi push sono attualmente iscritti o meno. Verrà fatto riferimento a questi valori in tutti gli snippet di codice.

Prima di registrare il file service-worker.js, che ha la logica per la gestione di un messaggio push, verifichiamo che i service worker siano supportati. In questo caso stiamo semplicemente comunicando al browser che questo file JavaScript è il service worker del nostro sito.

Configura lo stato iniziale

Esempio di UX dei messaggi push attivata e disattivata in Chrome.

Una volta registrato il service worker, occorre impostare lo stato della UI.

Gli utenti si aspettano di avere una semplice UI per attivare o disattivare i messaggi push per il tuo sito e che sia sempre al passo con le eventuali modifiche apportate. In altre parole, se abilitano i messaggi push per il tuo sito, esci e tornano una settimana dopo, la tua UI dovrebbe evidenziare che i messaggi push sono già abilitati.

Puoi trovare alcune linee guida sull'esperienza utente in questo documento. In questo articolo ci concentreremo sugli aspetti tecnici.

A questo punto potresti pensare che ci sono solo due stati da gestire, attivato o disattivato. Esistono però altri stati relativi alle notifiche che devi prendere in considerazione.

Un diagramma che evidenzia le diverse considerazioni e lo stato del push in Chrome

Dobbiamo verificare una serie di API prima di abilitare il pulsante e, se tutto è supportato, possiamo abilitare la nostra UI e impostare lo stato iniziale per indicare se i messaggi push sono iscritti o meno.

Poiché la maggior parte di questi controlli comporta la disattivazione della nostra UI, devi impostare lo stato iniziale su Disattivato. Inoltre, evita di creare confusione in caso di problemi con il codice JavaScript della pagina, ad esempio se non è possibile scaricare il file JS o se l'utente ha disattivato JavaScript.

<button class="js-push-button" disabled>
    Enable Push Messages
</button>

Con questo stato iniziale, possiamo eseguire i controlli descritti in precedenza nel metodo initialiseState(), ovvero dopo la registrazione del nostro service worker.

// Once the service worker is registered set the initial state
function initialiseState() {
    // Are Notifications supported in the service worker?
    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.warn('Notifications aren\'t supported.');
    return;
    }

    // Check the current Notification permission.
    // If its denied, it's a permanent block until the
    // user changes the permission
    if (Notification.permission === 'denied') {
    console.warn('The user has blocked notifications.');
    return;
    }

    // Check if push messaging is supported
    if (!('PushManager' in window)) {
    console.warn('Push messaging isn\'t supported.');
    return;
    }

    // We need the service worker registration to check for a subscription
    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
        .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        var pushButton = document.querySelector('.js-push-button');
        pushButton.disabled = false;

        if (!subscription) {
            // We aren't subscribed to push, so set UI
            // to allow the user to enable push
            return;
        }

        // Keep your server in sync with the latest subscriptionId
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
        })
        .catch(function(err) {
        console.warn('Error during getSubscription()', err);
        });
    });
}

Una breve panoramica di questi passaggi:

  • Verifichiamo che showNotification sia disponibile nel prototipo ServiceWorkerRegistration. In caso contrario, non saremo in grado di mostrare una notifica del nostro service worker quando viene ricevuto un messaggio push.
  • Controlliamo qual è l'attuale Notification.permission per assicurarci che non sia "denied". Un'autorizzazione negata significa che non puoi mostrare notifiche fino a quando l'utente non modifica manualmente l'autorizzazione nel browser.
  • Per verificare se i messaggi push sono supportati, verifichiamo che PushManager sia disponibile nell'oggetto finestra.
  • Infine, abbiamo usato pushManager.getSubscription() per verificare se avessimo già un abbonamento o meno. Se lo facciamo, inviamo i dettagli dell'abbonamento al nostro server per assicurarci di avere le informazioni corrette e impostiamo la nostra UI in modo da indicare che i messaggi push sono già abilitati o meno. Più avanti in questo articolo vedremo i dettagli presenti nell'oggetto abbonamento.

Attendiamo la risoluzione di navigator.serviceWorker.ready per controllare la disponibilità di un abbonamento e abilitare il pulsante push perché puoi effettivamente sottoscrivere l'abbonamento per i messaggi push solo dopo che il worker del servizio è attivo.

Il passaggio successivo consiste nel gestire il momento in cui l'utente vuole abilitare i messaggi push, ma prima di poterlo fare è necessario configurare un progetto della Google Developer Console e aggiungere alcuni parametri al file manifest per utilizzare Firebase Cloud Messaging (FCM), precedentemente noto come Google Cloud Messaging (GCM).

Crea un progetto nella Console per gli sviluppatori di Firebase

Chrome utilizza FCM per gestire l'invio e la consegna dei messaggi push; tuttavia, per utilizzare l'API FCM, devi configurare un progetto nella Console per gli sviluppatori di Firebase.

I seguenti passaggi sono specifici per Chrome, Opera per Android e Samsung che utilizzano FCM. Parleremo di come funzionerebbe in altri browser più avanti nell'articolo.

Crea un nuovo progetto di sviluppatore Firebase

Per iniziare, devi creare un nuovo progetto su https://console.firebase.google.com/ facendo clic su "Crea nuovo progetto".

Screenshot del nuovo progetto Firebase

Aggiungi un nome per il progetto, creane uno. Si aprirà la dashboard del progetto:

Home page del progetto Firebase

Da questa dashboard, fai clic sull'icona a forma di ingranaggio accanto al nome del progetto nell'angolo in alto a sinistra, quindi fai clic su "Impostazioni progetto".

Menu impostazioni progetto Firebase

Nella pagina delle impostazioni, fai clic sulla scheda "Cloud Messaging".

Menu di Firebase Project Cloud Messaging

Questa pagina contiene la chiave API per i messaggi push, che utilizzeremo in seguito, e l'ID mittente, che dovremo inserire nel file manifest dell'app web nella prossima sezione.

Aggiungi un manifest dell'app web

Per il push, dobbiamo aggiungere un file manifest con un campo gcm_sender_id, affinché la sottoscrizione push vada a buon fine. Questo parametro è richiesto solo da Chrome, Opera per Android e dai browser Samsung affinché possano utilizzare FCM / GCM.

gcm_sender_id viene utilizzato da questi browser quando sottoscrive l'abbonamento a un dispositivo degli utenti con FCM. Ciò significa che FCM può identificare il dispositivo dell'utente e assicurarsi che il tuo ID mittente corrisponda alla chiave API corrispondente e che l'utente abbia consentito al tuo server di inviare messaggi push.

Di seguito è riportato un semplicissimo file manifest:

{
    "name": "Push Demo",
    "short_name": "Push Demo",
    "icons": [{
        "src": "images/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
        }],
    "start_url": "/index.html?homescreen=1",
    "display": "standalone",
    "gcm_sender_id": "<Your Sender ID Here>"
}

Devi impostare il valore gcm_sender_id sull'ID mittente del tuo progetto Firebase.

Dopo aver salvato il file manifest nel progetto (manifest.json è un nome valido), fai riferimento al file HTML utilizzando il seguente tag nell'intestazione della pagina.

<link rel="manifest" href="/manifest.json">

Se non aggiungi un file manifest web con questi parametri, riceverai un'eccezione quando tenti di iscrivere l'utente ai messaggi push, con l'errore "Registration failed - no sender id provided" o "Registration failed - permission denied".

Iscriviti a Messaggistica push

Ora che hai configurato un file manifest, puoi tornare al codice JavaScript del tuo sito.

Per eseguire la sottoscrizione, devi chiamare il metodo subscribe() sull'oggetto PushManager, a cui accedi tramite ServiceWorkerRegistration.

All'utente verrà chiesto di concedere alla tua origine l'autorizzazione a inviare notifiche push. Senza questa autorizzazione, non potrai abbonarti.

Se la risposta promise restituita dal metodo subscribe() si risolve, ti verrà assegnato un oggetto PushSubscription che conterrà un endpoint.

L'endpoint deve essere salvato sul tuo server per ogni utente, poiché avrai bisogno di questi utenti per inviare messaggi push in un secondo momento.

Il seguente codice consente all'utente di iscriversi ai messaggi push:

function subscribe() {
    // Disable the button so it can't be changed while
    // we process the permission request
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe()
        .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        pushButton.textContent = 'Disable Push Messages';
        pushButton.disabled = false;

        // TODO: Send the subscription.endpoint to your server
        // and save it to send a push message at a later date
        return sendSubscriptionToServer(subscription);
        })
        .catch(function(e) {
        if (Notification.permission === 'denied') {
            // The user denied the notification permission which
            // means we failed to subscribe and the user will need
            // to manually change the notification permission to
            // subscribe to push messages
            console.warn('Permission for Notifications was denied');
            pushButton.disabled = true;
        } else {
            // A problem occurred with the subscription; common reasons
            // include network errors, and lacking gcm_sender_id and/or
            // gcm_user_visible_only in the manifest.
            console.error('Unable to subscribe to push.', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        }
        });
    });
}

A questo punto la tua applicazione web è pronta per ricevere un messaggio push, anche se non accadrà nulla finché non aggiungeremo un listener di eventi push al nostro file dei service worker.

Listener di eventi push per service worker

Quando viene ricevuto un messaggio push (parleremo di come inviare effettivamente un messaggio push nella prossima sezione), nel tuo service worker verrà inviato un evento push, a quel punto dovrai visualizzare una notifica.

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';

    event.waitUntil(
    self.registration.showNotification(title, {
        body: body,
        icon: icon,
        tag: tag
    })
    );
});

Questo codice registra un listener di eventi push e visualizza una notifica con un titolo, un corpo del testo, un'icona e un tag di notifica predefiniti. Una particolarità da evidenziare con questo esempio è il metodo event.waitUntil(). Questo metodo accetta una promessa ed estende la durata di un gestore di eventi (o può essere considerato come un mantenimento attivo del worker di servizio), fino a quando la promessa non viene risolta; in questo caso, la promessa passata a event.waitUntil è la promessa restituita da showNotification().

Il tag di notifica funge da identificatore per le notifiche univoche. Se abbiamo inviato due messaggi push allo stesso endpoint (con un breve ritardo tra loro e mostriamo notifiche con lo stesso tag), il browser mostrerà la prima notifica e la sostituirà con la seconda quando viene ricevuto il messaggio push.

Se vuoi mostrare più notifiche contemporaneamente, utilizza un altro tag o nessun tag. Più avanti in questo post esamineremo un esempio più completo della visualizzazione di una notifica. Per ora, cerchiamo di semplificare le cose e vediamo se l'invio di un messaggio push riceve questa notifica.

Invio di un messaggio push

Abbiamo effettuato l'iscrizione ai messaggi push e il nostro service worker è pronto a mostrare una notifica, quindi è il momento di inviare un messaggio push tramite FCM.

Questo vale solo per i browser che utilizzano FCM.

Quando invii la variabile PushSubscription.endpoint al tuo server, l'endpoint per FCM è speciale. Alla fine dell'URL c'è un parametro che è registration_id.

Un endpoint di esempio potrebbe essere:

https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

L'URL FCM è:

https://fcm.googleapis.com/fcm/send

Lo registration_id sarebbe:

APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

Si tratta di una funzionalità specifica per i browser che utilizzano FCM. In un browser normale, basta ottenere un endpoint, che viene chiamato in modo standard e che funziona indipendentemente dall'URL.

Ciò significa che sul tuo server dovrai verificare se l'endpoint è per FCM e, in tal caso, estrarre il registry_id. Per farlo in Python, potresti fare qualcosa come:

if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
    endpointParts = endpoint.split('/')
    registrationId = endpointParts[len(endpointParts) - 1]

    endpoint = 'https://fcm.googleapis.com/fcm/send'

Una volta ottenuto l'ID di registrazione, puoi effettuare una chiamata all'API di FCM. Qui sono disponibili documenti di riferimento sull'API FCM.

Gli aspetti principali da ricordare quando si chiama FCM sono:

  • Quando chiami l'API, è necessario impostare un'intestazione Authorization con il valore key=&lt;YOUR_API_KEY&gt;, dove &lt;YOUR_API_KEY&gt; è la chiave API del progetto Firebase.
    • La chiave API viene utilizzata da FCM per trovare l'ID mittente appropriato, assicurarti che l'utente abbia concesso l'autorizzazione per il tuo progetto e infine assicurarti che l'indirizzo IP del server sia inserito nella lista consentita per il progetto.
  • Un'intestazione Content-Type appropriata di application/json o application/x-www-form-urlencoded;charset=UTF-8, a seconda che i dati vengano inviati come JSON o come dati del modulo.
  • Un array di registration_ids: si tratta degli ID di registrazione che vuoi estrarre dagli endpoint degli utenti.

Consulta la documentazione su come inviare messaggi push dal tuo server, ma per un rapido controllo del tuo service worker puoi utilizzare cURL per inviare un messaggio push al tuo browser.

Sostituisci &lt;YOUR_API_KEY&gt; e &lt;YOUR_REGISTRATION_ID&gt; in questo comando cURL con i tuoi ed eseguilo da un terminale.

Dovresti vedere una notifica elegante:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
Esempio di un messaggio push da Chrome per Android.

Durante lo sviluppo della logica di backend, ricorda che l'intestazione e il formato di autorizzazione del corpo del POST sono specifici dell'endpoint FCM, quindi rileva quando l'endpoint è per FCM e aggiungi l'intestazione e formatta il corpo del POST in modo condizionale. Per altri browser (e, possibilmente, Chrome in futuro) dovrai implementare il Web Push Protocol.

Uno svantaggio dell'attuale implementazione dell'API Push in Chrome è che non è possibile inviare dati con un messaggio push. No, niente. Il motivo è che in una futura implementazione, i dati dei payload dovranno essere criptati sul server prima di essere inviati a un endpoint di messaggistica push. In questo modo l'endpoint, qualunque sia il provider push, non sarà in grado di visualizzare facilmente il contenuto del messaggio push. Questo protegge anche da altre vulnerabilità, come una convalida scadente dei certificati HTTPS e attacchi man in the middle tra il tuo server e il provider push. Tuttavia, questa crittografia non è ancora supportata, nel frattempo dovrai eseguire un recupero per ottenere le informazioni necessarie per compilare una notifica.

Esempio di evento push più completo

La notifica che abbiamo visto finora è piuttosto basilare e, per quanto riguarda gli esempi, è piuttosto scadente nel coprire un caso d'uso reale.

Realisticamente, la maggior parte delle persone vorrà ottenere alcune informazioni dal proprio server prima di visualizzare la notifica. Potrebbero essere dati per compilare il titolo e il messaggio della notifica con qualcosa di specifico o fare un ulteriore passo avanti e memorizzare nella cache alcune pagine o alcuni dati in modo che, quando l'utente fa clic sulla notifica, tutto diventa immediatamente disponibile all'apertura del browser, anche se la rete non è disponibile in quel momento.

Nel codice seguente recuperiamo alcuni dati da un'API, convertiamo la risposta in un oggetto e lo utilizziamo per completare la notifica.

self.addEventListener('push', function(event) {
    // Since there is no payload data with the first version
    // of push messages, we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(SOME_API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        // Either show a message to the user explaining the error
        // or enter a generic message and handle the
        // onnotificationclick event to direct the user to a web page
        console.log('Looks like there was a problem. Status Code: ' + response.status);
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        if (data.error || !data.notification) {
            console.error('The API returned an error.', data.error);
            throw new Error();
        }

        var title = data.notification.title;
        var message = data.notification.message;
        var icon = data.notification.icon;
        var notificationTag = data.notification.tag;

        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
        });
    }).catch(function(err) {
        console.error('Unable to retrieve data', err);

        var title = 'An error occurred';
        var message = 'We were unable to get the information for this push message';
        var icon = URL_TO_DEFAULT_ICON;
        var notificationTag = 'notification-error';
        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
    })
    );
});

Vale la pena sottolineare ancora una volta che event.waitUntil() accetta una promessa che risulta nella promessa restituita da showNotification(), il che significa che il nostro listener di eventi non si chiuderà fino a quando la chiamata fetch() asincrona non sarà completata e la notifica non verrà mostrata.

Vedrai una notifica anche se c'è un errore. in quanto, in caso contrario, Chrome mostrerà una sua notifica generica.

Apertura di un URL quando l'utente fa clic su una notifica

Quando l'utente fa clic su una notifica, viene inviato un evento notificationclick nel tuo service worker. All'interno del gestore, puoi eseguire l'azione appropriata, come impostare lo stato attivo su una scheda o aprire una finestra con un determinato URL.

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event.notification.tag);
    // Android doesn't close the notification when you click on it
    // See: http://crbug.com/463146
    event.notification.close();

    // This looks to see if the current is already open and
    // focuses if it is
    event.waitUntil(
    clients.matchAll({
        type: "window"
    })
    .then(function(clientList) {
        for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == '/' && 'focus' in client)
            return client.focus();
        }
        if (clients.openWindow) {
        return clients.openWindow('/');
        }
    })
    );
});

In questo esempio, il browser viene aperto alla directory radice dell'origine del sito, attivando una scheda della stessa origine esistente, se esistente, e aprendone una nuova.

Troverai un post dedicato ad alcune delle cose che puoi fare con l'API Notification qui.

Annullare l'iscrizione al dispositivo di un utente

Hai sottoscritto un abbonamento per il dispositivo di un utente che riceve messaggi push, ma come puoi annullare l'iscrizione?

Il principale requisito per annullare l'iscrizione sul dispositivo di un utente è chiamare il metodo unsubscribe() sull'oggetto PushSubscription e rimuovere l'endpoint dai tuoi server (per evitare di inviare messaggi push che sai che non verranno ricevuti). Il codice riportato di seguito funziona esattamente come segue:

function unsubscribe() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subscription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
        function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
            // No subscription object, so set the state
            // to allow the user to subscribe to push
            isPushEnabled = false;
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            return;
        }

        var subscriptionId = pushSubscription.subscriptionId;
        // TODO: Make a request to your server to remove
        // the subscriptionId from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subscription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            isPushEnabled = false;
        }).catch(function(e) {
            // We failed to unsubscribe, this can lead to
            // an unusual state, so may be best to remove
            // the users data from your data store and
            // inform the user that you have done so

            console.log('Unsubscription error: ', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        });
        }).catch(function(e) {
        console.error('Error thrown while unsubscribing from push messaging.', e);
        });
    });
}

Mantenere aggiornato l'abbonamento

Gli abbonamenti potrebbero non essere sincronizzati tra FCM e il tuo server. Assicurati che il tuo server analizzi il corpo della risposta del POST di invio dell'API FCM alla ricerca dei risultati error:NotRegistered e canonical_id, come spiegato nella documentazione di FCM.

Inoltre, gli abbonamenti potrebbero non essere sincronizzati tra il service worker e il server. Ad esempio, dopo aver effettuato l'iscrizione o l'annullamento dell'iscrizione correttamente, una connessione di rete instabile potrebbe impedirti di aggiornare il server oppure un utente potrebbe revocare l'autorizzazione alle notifiche, che attiva un'annullamento automatico dell'iscrizione. Gestisci questi casi controllando periodicamente il risultato di serviceWorkerRegistration.pushManager.getSubscription() (ad es. al caricamento della pagina) e sincronizzandolo con il server. Puoi anche abbonarti di nuovo automaticamente se non hai più un abbonamento e Notification.permission == 'granted'.

In sendSubscriptionToServer() dovrai considerare come gestisci le richieste di rete non riuscite durante l'aggiornamento di endpoint. Una soluzione è monitorare lo stato di endpoint in un cookie per determinare se il server ha bisogno o meno dei dettagli più recenti.

Tutti i passaggi precedenti si traducono in un'implementazione completa dei messaggi push sul web in Chrome 46. Sono ancora disponibili funzionalità specifiche che semplificano le cose (come un'API standard per l'attivazione di messaggi push), ma questa release ti consente di iniziare a integrare subito i messaggi push nelle tue app web.

Come eseguire il debug della tua app web

Durante l'implementazione dei messaggi push, i bug si trovano in una delle due posizioni seguenti: la tua pagina o il tuo service worker.

Puoi eseguire il debug dei bug nella pagina utilizzando DevTools. Per eseguire il debug dei problemi del service worker, hai due opzioni:

  1. Vai a chrome://inspect > Service worker. Questa vista contiene solo informazioni sui service worker attualmente in esecuzione.
  2. Vai all'indirizzo chrome://serviceworker-internals. Da qui puoi visualizzare lo stato dei service worker e visualizzare eventuali errori. Questa pagina è temporanea finché DevTools non offre un set di funzionalità simili.

Uno dei migliori suggerimenti che posso dare a chi è alle prime armi con i service worker è usare la casella di controllo "Apri la finestra di DevTools e metti in pausa l'esecuzione di JavaScript all'avvio del service worker per il debug". Questa casella di controllo aggiungerà un punto di interruzione all'inizio del service worker e metterà in pausa l'esecuzione. In questo modo, puoi riprendere o seguire lo script del service worker e vedere se si verificano problemi.

Screenshot che mostra dove si trova la casella di controllo per mettere in pausa l&#39;esecuzione in serviceworker-internals.

Se sembra esserci un problema tra FCM e l'evento push del tuo service worker, non puoi fare molto per eseguirne il debug, dal momento che non puoi vedere se Chrome ha ricevuto qualcosa. La cosa fondamentale da verificare è che la risposta da FCM abbia esito positivo quando il server effettua una chiamata API. Sarà simile a questo:

{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}

Osserva la risposta "success": 1. Se viene invece visualizzato un errore, ciò indica che qualcosa non va con l'ID di registrazione FCM e che il messaggio push non viene inviato a Chrome.

Debug dei service worker su Chrome per Android

Al momento il debug dei service worker su Chrome per Android non è ovvio. Devi accedere alla pagina chrome://inspect, trovare il tuo dispositivo e cercare un elemento dell'elenco con il nome "Worker pid:....", che ha l'URL del service worker.

Screenshot che mostra dove vivono i Service worker in Chrome Inspect

UX per le notifiche push

Il team di Chrome ha realizzato un documento di best practice per l'esperienza utente delle notifiche push e un documento che illustra alcuni dei casi limite legati all'utilizzo delle notifiche push.

Il futuro dei messaggi push su Chrome e sul web aperto

Questa sezione approfondisce alcune delle parti specifiche di questa implementazione di Chrome che dovresti conoscere e le differenze con altre implementazioni del browser.

Web Push Protocol ed endpoint

L'aspetto positivo dello standard dell'API Push è che dovresti essere in grado di prendere l'endpoint, passarlo al tuo server e inviare messaggi push implementando il Web Push Protocol.

Il Web Push Protocol è un nuovo standard che i provider di push possono implementare, consentendo agli sviluppatori di non doversi preoccupare dell'identità del provider. L'idea è che in questo modo eviterai la necessità di registrarsi per le chiavi API e di inviare dati formattati appositamente, come con FCM.

Chrome è stato il primo browser a implementare l'API Push e FCM non supporta il Web Push Protocol. Questo è il motivo per cui Chrome richiede l'gcm_sender_id e devi utilizzare l'API RESTful per FCM.

L'obiettivo finale di Chrome è utilizzare il Web Push Protocol con Chrome e FCM.

Fino ad allora, devi rilevare l'endpoint "https://fcm.googleapis.com/fcm/send" e gestirlo separatamente dagli altri endpoint, ad esempio formattare i dati del payload in modo specifico e aggiungere la chiave di autorizzazione.

Come implementare il Web Push Protocol?

Al momento Firefox Nightly sta lavorando alla tecnologia push e sarà probabilmente il primo browser a implementare il protocollo web push.

Domande frequenti

Dove si trovano le specifiche?

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/

Posso evitare notifiche duplicate se la mia presenza sul web ha più origini o se ho sia una presenza sul web sia una nativa?

Al momento non è disponibile una soluzione, ma puoi seguire i progressi su Chromium.

Lo scenario ideale sarebbe quello di avere un qualche tipo di ID per il dispositivo di un utente, quindi sul lato server di abbinare gli ID abbonamento dell'app nativa e dell'app web e decidere a quale inviare un messaggio push. È possibile farlo tramite le dimensioni dello schermo, il modello del dispositivo e la condivisione di una chiave generata tra l'app web e l'app nativa, ma ciascun approccio ha i pro e i contro.

Perché mi serve un gcm_sender_id?

Questa operazione è necessaria per consentire a Chrome, Opera per Android e al browser Samsung di utilizzare l'API Firebase Cloud Messaging (FCM). L'obiettivo è utilizzare il Web Push Protocol quando lo standard è finalizzato e FCM può supportarlo.

Perché non utilizzare web Socket o eventi inviati dal server (EventSource)?

Il vantaggio dell'utilizzo dei messaggi push è che anche se la pagina è chiusa, il service worker verrà riattivato e potrà visualizzare una notifica. La connessione di Web Sockets ed EventSource viene chiusa quando la pagina o il browser vengono chiusi.

Cosa devo fare se non mi serve l'invio di eventi in background?

Se non hai bisogno dell'invio in background, i web Sockets sono un'ottima opzione.

Quando posso utilizzare la funzionalità push senza mostrare le notifiche (ad esempio, la modalità push silenzioso in background)?

Non è prevista alcuna tempistica per la disponibilità di questa funzionalità, ma è l'intenzione di implementare la sincronizzazione in background e, sebbene non sia stata decisa o specificata, si discute dell'abilitazione del push silenzioso con la sincronizzazione in background.

Perché è richiesto HTTPS? Come posso risolvere il problema durante lo sviluppo?

I service worker richiedono origini sicure per garantire che lo script del service worker provenga dall'origine prevista e non abbia avuto origine da un attacco man in the middle. Attualmente, ciò significa utilizzare HTTPS sui siti attivi, anche se localhost funzionerà durante lo sviluppo.

Com'è il supporto dei browser?

Chrome supporta nella sua versione stabile e Mozilla ha iniziato a lavorare anche in Firefox Nightly. Per ulteriori informazioni, consulta il bug relativo all'implementazione dell'API Push e controlla l'implementazione delle notifiche qui.

Posso rimuovere una notifica dopo un determinato periodo di tempo?

Al momento non è possibile, ma abbiamo intenzione di aggiungere un supporto per ottenere un elenco delle notifiche attualmente visibili. Se ti capita di usare un caso d'uso per impostare una scadenza per la notifica dopo la creazione, ci piacerebbe sapere di cosa si tratta, quindi aggiungi un commento e provvederemo a ritrasmetterlo al team di Chrome.

Se devi interrompere l'invio di una notifica push all'utente solo dopo un determinato periodo di tempo e non è importante per quanto tempo la notifica rimane visibile, puoi utilizzare il parametro Time to Live (TTL) di FCM, scopri di più qui.

Quali sono i limiti dei messaggi push in Chrome?

Questo post presenta alcune limitazioni:

  • L'utilizzo di CCM come servizio push da parte di Chrome crea una serie di requisiti di proprietà. Stiamo lavorando insieme per vedere se alcuni di questi problemi possono essere rimossi in futuro.
  • Quando ricevi un messaggio push, devi mostrare una notifica.
  • Chrome su computer ha un'avvertenza: se il servizio non è in esecuzione, i messaggi push non verranno ricevuti. Ciò differisce da ChromeOS e Android, che prevedono sempre la ricezione dei messaggi push.

Non dovremmo usare l'APIPermissions?

L'API Authorization è implementata in Chrome, ma non è necessariamente disponibile in tutti i browser. Puoi scoprire di più qui.

Perché Chrome non apre la scheda precedente quando faccio clic su una notifica?

Questo problema riguarda solo le pagine che non sono attualmente controllate da un service worker. Puoi scoprire ulteriori informazioni qui.

Cosa succede se una notifica non è aggiornata nel momento in cui il dispositivo dell'utente ha ricevuto il push?

Quando ricevi un messaggio push, devi sempre mostrare una notifica. Se vuoi inviare una notifica, che però è utile solo per un determinato periodo di tempo, puoi utilizzare il parametro "time_to_live" su CCM in modo che FCM non invii il messaggio push se supera la data di scadenza.

Ulteriori dettagli sono disponibili qui.

Che cosa succede se invio 10 messaggi push ma voglio che il dispositivo ne riceva solo uno?

FCM ha un parametro "compress_key" che puoi utilizzare per indicare a FCM di sostituire eventuali messaggi in sospeso che hanno lo stesso valore "compress_key" con il nuovo messaggio.

Ulteriori dettagli sono disponibili qui.