Notifiche delle modifiche apportate alle notifiche

Matt Gaunt

Innanzitutto, mi scuso per quel titolo pessimo, ma non ho potuto.

In Chrome 44 vengono aggiunti Notfication.data e ServiceWorkerRegistration.getNotifications() per aprire / semplificare alcuni casi d'uso comuni relativi alla gestione delle notifiche con messaggi push.

Dati notifica

Notification.data consente di associare un oggetto JavaScript a una notifica.

In sostanza, questo è il risultato: quando ricevi un messaggio push, puoi creare una notifica con alcuni dati e, nell'evento notificationclick, puoi ricevere la notifica su cui è stato fatto clic e recuperare i dati.

Ad esempio, creando un oggetto dati e aggiungendolo alle opzioni di notifica, come indicato di seguito:

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';
    var data = {
    doge: {
        wow: 'such amaze notification data'
    }
    };

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

Questo significa che possiamo ottenere le informazioni relative all'evento notificationclick:

self.addEventListener('notificationclick', function(event) {
    var doge = event.notification.data.doge;
    console.log(doge.wow);
});

Prima dovevi archiviare i dati in IndexDB o inserire qualcosa alla fine dell'URL dell'icona, ad esempio.

ServiceWorkerRegistration.getNotifications()

Una richiesta comune da parte degli sviluppatori che lavorano alle notifiche push è quella di avere un migliore controllo sulle notifiche visualizzate.

Un caso d'uso di esempio potrebbe essere un'applicazione di chat in cui un utente invia più messaggi e il destinatario visualizza più notifiche. Idealmente, l'app web potrebbe rilevare diverse notifiche che non sono state visualizzate e comprimerle in un'unica notifica.

Senza getNotifiche(), il meglio che puoi fare è sostituire la notifica precedente con il messaggio più recente. Con getNotifiche(), puoi "comprimere" le notifiche se ne è già visualizzata una, il che si traduce in un'esperienza utente molto migliore.

Esempio di raggruppamento delle notifiche.

Il codice per eseguire questa operazione è relativamente semplice. All'interno dell'evento push, chiama ServiceWorkerRegistration.get Notifications() per ricevere un array di notifiche correnti e da lì decidi il comportamento corretto, ad esempio comprimere tutte le notifiche o utilizzare Notification.tag.

function showNotification(title, body, icon, data) {
    var notificationOptions = {
    body: body,
    icon: icon ? icon : 'images/touch/chrome-touch-icon-192x192.png',
    tag: 'simple-push-demo-notification',
    data: data
    };

    self.registration.showNotification(title, notificationOptions);
    return;
}

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

    // Since this is no payload data with the first version
    // of Push notifications, here we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
            response.status);
        // Throw an error so the promise is rejected and catch() is executed
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        var title = 'You have a new message';
        var message = data.message;
        var icon = 'images/notification-icon.png';
        var notificationTag = 'chat-message';

        var notificationFilter = {
            tag: notificationTag
        };
        return self.registration.getNotifications(notificationFilter)
            .then(function(notifications) {
            if (notifications && notifications.length > 0) {
                // Start with one to account for the new notification
                // we are adding
                var notificationCount = 1;
                for (var i = 0; i < notifications.length; i++) {
                var existingNotification = notifications[i];
                if (existingNotification.data &&
                    existingNotification.data.notificationCount) {
                    notificationCount +=
existingNotification.data.notificationCount;
                } else {
                    notificationCount++;
                }
                existingNotification.close();
                }
                message = 'You have ' + notificationCount +
                ' weather updates.';
                notificationData.notificationCount = notificationCount;
            }

            return showNotification(title, message, icon, notificationData);
            });
        });
    }).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';

        return showNotification(title, message);
    })
    );
});

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event);

    if (Notification.prototype.hasOwnProperty('data')) {
    console.log('Using Data');
    var url = event.notification.data.url;
    event.waitUntil(clients.openWindow(url));
    } else {
    event.waitUntil(getIdb().get(KEY_VALUE_STORE_NAME,
event.notification.tag).then(function(url) {
        // At the moment you cannot open third party URL's, a simple trick
        // is to redirect to the desired URL from a URL on your domain
        var redirectUrl = '/redirect.html?redirect=' +
        url;
        return clients.openWindow(redirectUrl);
    }));
    }
});

La prima cosa da evidenziare con questo snippet di codice è che filtriamo le nostre notifiche passando un oggetto filtro a getNotifiche(). Ciò significa che possiamo ricevere un elenco di notifiche per un tag specifico (in questo esempio per una determinata conversazione).

var notificationFilter = {
    tag: notificationTag
};
return self.registration.getNotifications(notificationFilter)

Dopodiché esaminiamo le notifiche visibili e verifichiamo se esiste un numero di notifiche associato alla notifica e l'incremento in base a questo. In questo modo, se viene visualizzata una notifica che indica all'utente che ci sono due messaggi da leggere, vorremmo sottolineare che ci sono tre messaggi da leggere quando arriva un nuovo push.

var notificationCount = 1;
for (var i = 0; i < notifications.length; i++) {
    var existingNotification = notifications[i];
    if (existingNotification.data && existingNotification.data.notificationCount) {
    notificationCount += existingNotification.data.notificationCount;
    } else {
    notificationCount++;
    }
    existingNotification.close();
}

Un dettaglio da evidenziare è che devi chiamare close() nella notifica per assicurarti che la notifica venga rimossa dall'elenco delle notifiche. Questo è un bug di Chrome poiché ogni notifica viene sostituita dalla successiva perché viene utilizzato lo stesso tag. Al momento questa sostituzione non si riflette nell'array restituito da getNotifications().

Questo è solo un esempio di getNotifiche() e, come potete immaginare, questa API apre una serie di altri casi d'uso.

NotificationOptions.vibrate

A partire da Chrome 45, puoi specificare un tipo di vibrazione durante la creazione di una notifica. Sui dispositivi che supportano l'API Vibration (attualmente solo Chrome per Android), questa opzione consente di personalizzare il tipo di vibrazione che verrà utilizzato quando viene visualizzata la notifica.

Un modello di vibrazione può essere un array di numeri o un singolo numero che viene trattato come un array di un numero. I valori nell'array rappresentano i tempi in millisecondi, dove gli indici pari (0, 2, 4 e così via) rappresentano la durata della vibrazione e gli indici dispari indicano la durata della pausa prima della vibrazione successiva.

self.registration.showNotification('Buzz!', {
    body: 'Bzzz bzzzz',
    vibrate: [300, 100, 400] // Vibrate 300ms, pause 100ms, then vibrate 400ms
});

Richieste di funzionalità comuni rimanenti

L'unica funzione comune che rimane richiesta agli sviluppatori è la possibilità di chiudere una notifica dopo un determinato periodo di tempo o la possibilità di inviare una notifica push con lo scopo di chiudere semplicemente una notifica, se visibile.

Al momento non c'è un modo per farlo e le specifiche non lo consentono, ma il team tecnico di Chrome è a conoscenza di questo caso d'uso.

Notifiche Android

Su computer, puoi creare una notifica con il seguente codice:

new Notification('Hello', {body: 'Yay!'});

Questa funzionalità non è mai stata supportata su Android a causa delle restrizioni della piattaforma: in particolare, Chrome non può supportare i callback sull'oggetto Notification, come onclick. Viene usato però sul desktop per visualizzare le notifiche delle app web attualmente aperte.

L'unico motivo per cui ho parlato è che in origine, un semplice rilevamento delle funzionalità come quello di seguito ti avrebbe aiutato a supportare la versione desktop senza causare errori su Android:

if (!'Notification' in window) {
    // Notifications aren't supported
    return;
}

Tuttavia, con il supporto delle notifiche push ora su Chrome per Android, le notifiche possono essere create da un ServiceWorker, ma non da una pagina web, il che significa che il rilevamento di questa funzionalità non è più appropriato. Se provi a creare una notifica su Chrome per Android, riceverai questo messaggio di errore:

_Uncaught TypeError: Failed to construct 'Notification': Illegal constructor.
Use ServiceWorkerRegistration.showNotification() instead_

Il modo migliore per rilevare le funzionalità per Android e desktop è svolgere le seguenti operazioni:

    function isNewNotificationSupported() {
        if (!window.Notification || !Notification.requestPermission)
            return false;
        if (Notification.permission == 'granted')
            throw new Error('You must only call this \*before\* calling
    Notification.requestPermission(), otherwise this feature detect would bug the
    user with an actual notification!');
        try {
            new Notification('');
        } catch (e) {
            if (e.name == 'TypeError')
                return false;
        }
        return true;
    }

Questa funzione può essere utilizzata nel seguente modo:

    if (window.Notification && Notification.permission == 'granted') {
        // We would only have prompted the user for permission if new
        // Notification was supported (see below), so assume it is supported.
        doStuffThatUsesNewNotification();
    } else if (isNewNotificationSupported()) {
        // new Notification is supported, so prompt the user for permission.
        showOptInUIForNotifications();
    }