Notifiche push sul Web aperto

Matt Gaunt

Se chiedi a un gruppo di sviluppatori quali funzionalità per dispositivi mobili mancano sul web, le notifiche push sono sempre in cima alla lista.

Le notifiche push consentono agli utenti di attivare gli aggiornamenti tempestivi dei siti che amano e ti permettono di coinvolgerli nuovamente in modo efficace con contenuti personalizzati e coinvolgenti.

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

L'API Push in Chrome si basa su alcune tecnologie diverse, tra cui i manifest delle app web e i service worker. In questo post esamineremo ciascuna di queste tecnologie, ma solo il minimo necessario per avviare i messaggi push. Per comprendere meglio alcune delle altre funzionalità dei manifest e le funzionalità offline dei service worker, consulta i link sopra.

Esamineremo anche cosa verrà aggiunto all'API nelle versioni future di Chrome e infine avremo una sezione di domande frequenti.

Implementazione della messaggistica push per Chrome

Questa sezione descrive ogni passaggio da completare per supportare i messaggi push nella tua app web.

Registra un service worker

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

Di seguito è riportato un esempio di come registrare un worker di servizio nella tua app web. Al termine della registrazione, viene chiamata la funzione initialiseState(), che illustreremo 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 del pulsante iscrive o annulla l'iscrizione dell'utente ai messaggi push. isPushEnabled è una variabile globale che monitora semplicemente se i messaggi push sono attualmente sottoscritti o meno. A questi verrà fatto riferimento in tutti gli snippet di codice.

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

Configurare lo stato iniziale

Esempio di UX di messaggistica push attivata e disattivata in Chrome.

Una volta registrato il service worker, dobbiamo configurare lo stato dell'interfaccia utente.

Gli utenti si aspettano un'interfaccia utente semplice per attivare o disattivare i messaggi push per il tuo sito e si aspettano che sia aggiornata in base alle modifiche apportate. In altre parole, se attivano i messaggi push per il tuo sito, esci e torna una settimana dopo, la tua UI dovrebbe evidenziare che i messaggi push sono già attivati.

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 siano solo due stati da gestire: attivo o disattivato. Tuttavia, ci sono altri stati relativi alle notifiche che devi prendere in considerazione.

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

Prima di attivare il pulsante, dobbiamo controllare una serie di API e, se tutto è supportato, possiamo attivare la nostra UI e impostare lo stato iniziale per indicare se la messaggistica push è attivata o meno.

Poiché la maggior parte di questi controlli comporta la disattivazione dell'interfaccia utente, devi impostare lo stato iniziale su disattivato. In questo modo, eviterai anche confusione nel caso in cui si verifichi un problema con il codice JavaScript della pagina, ad esempio se il file JS non può essere scaricato 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 sopra 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. Senza questa autorizzazione, non potremo mostrare una notifica del nostro service worker quando viene ricevuto un messaggio push.
  • Controlliamo qual è il valore corrente di Notification.permission per assicurarci che non sia "denied". Un'autorizzazione negata significa che non puoi mostrare le notifiche fino a quando l'utente non modifica manualmente l'autorizzazione nel browser.
  • Per verificare se la messaggistica push è supportata, controlliamo che PushManager sia disponibile nell'oggetto window.
  • Infine, abbiamo utilizzato pushManager.getSubscription() per verificare se abbiamo già un abbonamento. In questo caso, inviamo i dettagli dell'iscrizione al nostro server per assicurarci di disporre delle informazioni corrette e impostare la nostra UI in modo da indicare se la messaggistica push è già attivata o meno. Più avanti in questo articolo esamineremo i dettagli presenti nell'oggetto subscription.

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 attivare i messaggi push, ma prima di poterlo fare, dobbiamo configurare un progetto Google Developers Console e aggiungere alcuni parametri al file manifest per utilizzare Firebase Cloud Messaging (FCM), precedentemente noto come Google Cloud Messaging (GCM).

Creare un progetto nella console per sviluppatori 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 sviluppatori Firebase.

I passaggi che seguono sono specifici per Chrome, Opera per Android e il browser Samsung che utilizzano FCM. Più avanti nell'articolo parleremo di come funziona in altri browser.

Creare un nuovo progetto per sviluppatori 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

In questa dashboard, fai clic sull'ingranaggio accanto al nome del progetto nell'angolo superiore sinistro e poi su "Impostazioni progetto".

Menu Impostazioni progetto Firebase

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

Menu Firebase Cloud Messaging del progetto

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

Aggiungi un manifest dell'app web

Per le notifiche push, dobbiamo aggiungere un file manifest con un campo gcm_sender_id per far sì che l'abbonamento alle notifiche push vada a buon fine. Questo parametro è obbligatorio solo per Chrome, Opera per Android e il browser Samsung per poter utilizzare FCM / GCM.

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

Di seguito è riportato un file manifest molto semplice:

{
    "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 buon nome), fai riferimento al file HTML con il seguente tag nell'head 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".

Iscriversi ai messaggi push

Ora che hai configurato un manifest, puoi tornare al codice JavaScript dei tuoi siti.

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

L'utente dovrà autorizzare la tua origine a inviare notifiche push. Senza questa autorizzazione, non potrai abbonarti.

Se la promessa restituita dal metodo subscribe() viene risolta, ti verrà fornito un oggetto PushSubscription che conterrà un endpoint.

L'endpoint deve essere salvato sul server per ogni utente, poiché ti serviranno 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 app web è pronta per ricevere un messaggio push, anche se non accade nulla finché non aggiungi un gestore di eventi push al file del tuo worker di servizio.

Listener di eventi push del service worker

Quando viene ricevuto un messaggio push (parleremo di come inviare effettivamente un messaggio push nella sezione successiva), nel tuo service worker viene inviato un evento push, a quel punto dovrai mostrare 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 mostra una notifica con un titolo, un testo, un'icona e un tag di notifica predefiniti. Una particolarità da evidenziare con questo esempio è il metodo event.waitUntil(). Questo metodo riceve una promessa ed estende la durata di un gestore di eventi (o può essere considerato come un mantenimento attivo del servizio lavorare), fino a quando la promessa non viene risoluta; 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 inviamo due messaggi push allo stesso endpoint, con un breve intervallo tra loro, e mostriamo le 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 tag diverso o nessun tag. Più avanti in questo post esamineremo un esempio più completo di visualizzazione di una notifica. Per il momento, manteniamo la semplicità e vediamo se l'invio di un messaggio push mostra 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 server, il punto di interruzione per FCM è speciale. Ha un parametro alla fine dell'URL che è un registration_id.

Un endpoint di esempio è:

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

registration_id sarà:

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

Questo comportamento è specifico per i browser che utilizzano FCM. In un browser normale, puoi semplicemente ottenere un endpoint e chiamarlo in modo standard e funziona indipendentemente dall'URL.

Ciò significa che sul tuo server dovrai verificare se l'endpoint è per FCM e, in caso affermativo, estrarne il logging_id. Per farlo in Python, potresti fare qualcosa di simile:

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 registrazione, puoi effettuare una chiamata all'API FCM. Qui sono disponibili documenti di riferimento sull'API FCM.

Gli aspetti chiave da ricordare quando chiami 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, verificare che l'utente abbia concesso l'autorizzazione per il progetto e infine assicurarsi 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 registrazione che estrarresti dagli endpoint dei tuoi utenti.

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

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

Dovresti vedere una notifica:

    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.

Quando sviluppi la logica di backend, ricorda che l'intestazione di autorizzazione e il formato 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, si spera, in futuro per Chrome) dovrai implementare il protocollo Web Push.

Un svantaggio dell'attuale implementazione dell'API Push in Chrome è che non puoi inviare dati con un messaggio push. No, niente. Il motivo è che in un'implementazione futura, i dati del payload dovranno essere criptati sul tuo 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. Inoltre, protegge da altre vulnerabilità come la scarsa convalida dei certificati HTTPS e gli attacchi man in the middle tra il tuo server e il provider push. Tuttavia, questa crittografia non è ancora supportata, quindi nel frattempo dovrai eseguire un recupero per ottenere le informazioni necessarie per compilare una notifica.

Un esempio più completo di evento push

La notifica che abbiamo visto finora è piuttosto di base e, per quanto riguarda i sample, non è molto efficace per coprire un caso d'uso reale.

In realtà, la maggior parte degli utenti vorrà ricevere 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 oppure, andando oltre, memorizzare nella cache alcune pagine o dati in modo che, quando l'utente fa clic sulla notifica, tutto sia immediatamente disponibile quando il browser viene aperto, 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 la utilizziamo per compilare 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 si traduce nella promessa restituita da showNotification(), il che significa che il nostro listener di eventi non uscirà finché la chiamata asincrona fetch() non sarà completata e la notifica non verrà visualizzata.

Noterai che viene visualizzata una notifica anche in caso di errore. Questo accade perché, in caso contrario, Chrome mostrerà la propria 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 intraprendere l'azione appropriata, ad esempio mettere a fuoco 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('/');
        }
    })
    );
});

Questo esempio apre il browser nella directory principale dell'origine del sito, mettendo in primo piano una scheda esistente della stessa origine, se esistente, o aprendone una nuova.

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

Annullare l'iscrizione del dispositivo di un utente

Hai effettuato la registrazione del dispositivo di un utente e l'utente sta ricevendo messaggi push, ma come puoi annullare la registrazione?

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 fa esattamente questo:

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

Le iscrizioni potrebbero non essere sincronizzate tra FCM e il tuo server. Assicurati che il tuo server analizzi il corpo della risposta dell'invio POST dell'API FCM, cercando i 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 correttamente l'iscrizione o l'annullamento dell'iscrizione, 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. Potresti anche scegliere di eseguire nuovamente la registrazione automaticamente se non hai più un abbonamento e Notification.permission == "granted".

In sendSubscriptionToServer() dovrai considerare come gestire le richieste di rete non riuscite durante l'aggiornamento del 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 comportano un'implementazione completa della messaggistica push sul web in Chrome 46. Esistono ancora funzionalità specifiche che semplificano le cose (ad esempio un'API standard per l'attivazione dei messaggi push), ma questa release ti consente di iniziare a integrare i messaggi push nelle tue app web oggi stesso.

Come eseguire il debug dell'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.

I bug nella pagina possono essere sottoposti a debug utilizzando DevTools. Per eseguire il debug dei problemi relativi ai worker di servizio, hai due opzioni:

  1. Vai a chrome://inspect > Service worker. Questa visualizzazione non fornisce molte informazioni oltre a quelle relative ai service worker in esecuzione.
  2. Vai all'indirizzo chrome://serviceworker-internals. Da qui puoi visualizzare lo stato dei service worker e visualizzare gli eventuali errori. Questa pagina è provvisoria finché DevTools non avrà un insieme di funzionalità simile.

Uno dei migliori suggerimenti che posso dare a chi non ha dimestichezza con i worker di servizio è di utilizzare la casella di controllo "Apri finestra DevTools e metti in pausa l'esecuzione di JavaScript all'avvio del worker di servizio per il debug". Questa casella di controllo aggiungerà un punto di interruzione all'inizio del tuo worker di servizio e metterà in pausa l'esecuzione, in modo da poter riprendere o eseguire la procedura passo passo dello script del worker di servizio e verificare se si verificano problemi.

Screenshot che mostra dove si trova la casella di controllo di interruzione dell&#39;esecuzione in serviceworker-internals.

Se sembra esserci un problema tra FCM e l'evento push del tuo service worker, non c'è molto che puoi fare per eseguire il debug del problema, poiché non c'è modo per scoprire se Chrome ha ricevuto qualcosa. L'aspetto fondamentale da verificare è che la risposta da FCM abbia esito positivo quando il server effettua una chiamata API. L'aspetto sarà simile al seguente:

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

Nota 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 worker di servizio su Chrome per Android non è ovvio. Devi andare su chrome://inspect, trovare il tuo dispositivo e cercare un elemento dell'elenco con il nome "PID utente:…." che contiene l'URL del tuo utente servizio.

Screenshot che mostra dove si trovano i worker di servizio in Chrome Inspect

UX per le notifiche push

Il team di Chrome sta preparando un documento con le best practice per l'esperienza utente delle notifiche push, nonché un documento che illustra alcuni casi limite quando si utilizzano le notifiche push.

Il futuro della messaggistica 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.

Protocollo e endpoint web push

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

Il Web Push Protocol è un nuovo standard che i provider di push possono implementare, consentendo agli sviluppatori di non doversi preoccupare di sapere chi sia. L'idea è che in questo modo eviterai la necessità di registrarsi per le chiavi API e di inviare dati appositamente formattati, 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 è passare all'utilizzo del protocollo Web Push con Chrome e FCM.

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

Come implementare il Web Push Protocol?

Al momento, Firefox Nightly è in fase di implementazione delle notifiche push e probabilmente sarà il primo browser a implementare il protocollo Web Push.

Domande frequenti

Dove sono 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 che una nativa?

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

Lo scenario ideale sarebbe avere un qualche tipo di ID per il dispositivo di un utente e poi, sul lato server, abbinare gli ID abbonamento dell'app nativa e dell'app web e decidere a quale inviare un messaggio push. Puoi farlo in base alle dimensioni dello schermo, al modello di dispositivo, condividendo una chiave generata tra l'app web e l'app nativa, ma ogni approccio ha pro e contro.

Perché mi serve un gcm_sender_id?

Questo è necessario affinché Chrome, Opera per Android e il browser Samsung possano 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 servizio worker verrà riattivato e potrà mostrare 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 di caricamenti in background, Web Sockets è un'ottima opzione.

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

Non è ancora stata stabilita una tempistica per la disponibilità, ma c'è l'intenzione di implementare la sincronizzazione in background e, anche se non è stata presa una decisione o specificata, si discute di attivare push silenziosi con la sincronizzazione in background.

Perché è necessario HTTPS? Come faccio ad aggirare 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. Al momento, ciò significa utilizzare HTTPS sui siti pubblicati, anche se localhost funzionerà durante lo sviluppo.

Che aspetto ha il supporto del browser?

Chrome lo supporta nella sua versione stabile e Mozilla sta lavorando al push in Firefox Nightly. Per ulteriori informazioni, consulta il bug relativo all'implementazione dell'API Push e puoi monitorare l'implementazione delle notifiche qui.

Posso rimuovere una notifica dopo un determinato periodo di tempo?

Al momento non è possibile, ma prevediamo di aggiungere il supporto per ricevere un elenco delle notifiche attualmente visibili. Se hai un caso d'uso per impostare una scadenza per la notifica dopo che è stata visualizzata, saremo lieti di saperne di più. Aggiungi un commento e lo inoltreremo al team di Chrome.

Se devi solo interrompere l'invio di una notifica push all'utente dopo un determinato periodo di tempo e non ti interessa quanto rimane visualizzata la notifica, puoi utilizzare il parametro TTL (time to live) di FCM. Scopri di più qui.

Quali sono le limitazioni della messaggistica push in Chrome?

Questo post illustra alcune limitazioni:

  • L'utilizzo di CCM come servizio push da parte di Chrome crea una serie di requisiti di proprietà. Stiamo collaborando per capire se alcune di queste limitazioni possono essere rimosse in futuro.
  • Quando ricevi un messaggio push, devi mostrare una notifica.
  • Chrome su computer ha il vantaggio che, se non è in esecuzione, i messaggi push non verranno ricevuti. Ciò è diverso da ChromeOS e Android, dove i messaggi push vengono sempre ricevuti.

Non dovremmo utilizzare l'API Permissions?

L'API Permission è implementata in Chrome, ma non sarà necessariamente disponibile in tutti i browser. Scopri di più qui.

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

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

Che cosa succede se una notifica non è aggiornata al momento in cui il dispositivo dell'utente riceve il push?

Devi sempre mostrare una notifica quando ricevi un messaggio push. 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.

Puoi trovare ulteriori dettagli qui.

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

FCM ha un parametro "collapse_key" che puoi utilizzare per indicare a FCM di sostituire qualsiasi messaggio in attesa con lo stesso "collapse_key" con il nuovo messaggio.

Ulteriori dettagli sono disponibili qui.