Notifiche delle modifiche apportate alle notifiche

Matt Gaunt

Innanzitutto, mi scuso per il titolo orribile, ma non potevo non farlo.

In Chrome 44 sono stati aggiunti Notfication.data e ServiceWorkerRegistration.getNotifications() e consentono di gestire / semplificare alcuni casi d'uso comuni relativi alle notifiche con messaggi push.

Dati di notifica

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

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

Ad esempio, puoi creare un oggetto dati e aggiungerlo alle opzioni di notifica come segue:

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
    })
    );
});

Significa che possiamo ottenere le informazioni nell'evento notificationclick:

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

In precedenza, dovevi nascondere i dati in IndexDB o inserire qualcosa alla fine dell'URL icona.

ServiceWorkerRegistration.getNotifications()

Una richiesta comune degli sviluppatori che si occupano di notifiche push è avere un controllo migliore sulle notifiche visualizzate.

Un esempio di caso d'uso è un'applicazione di chat in cui un utente invia più messaggi e il destinatario visualizza più notifiche. Idealmente, l'app web dovrebbe essere in grado di rilevare che hai diverse notifiche non visualizzate e raggrupparle in una singola notifica.

Senza getNotifications(), il meglio che puoi fare è sostituire la notifica precedente con il messaggio più recente. Con getNotifications(), puoi "chiudere" le notifiche se ne è già visualizzata una, migliorando così l'esperienza utente.

Esempio di raggruppamento delle notifiche.

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

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 sottolineare con questo snippet di codice è che filtriamo le notifiche passando un oggetto filtro a getNotifications(). Ciò significa che possiamo ottenere un elenco di notifiche per un tag specifico (in questo esempio per una conversazione specifica).

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

Poi esaminiamo le notifiche visibili e controlliamo se è associato un conteggio delle notifiche e lo incrementiamo in base a questo. In questo modo, se una notifica indica all'utente che ci sono due messaggi da leggere, vogliamo segnalare che ce ne sono tre quando arriva una nuova notifica 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'ulteriore informazione da sottolineare è che devi chiamare close() sulla notifica per assicurarti che venga rimossa dall'elenco delle notifiche. Si tratta di un bug di Chrome, poiché ogni notifica viene sostituita dalla successiva perché viene utilizzato lo stesso tag. Al momento questa sostituzione non viene applicata all'array restituito da getNotifications().

Questo è solo un esempio di getNotifications() e, come puoi immaginare, questa API offre una serie di altri casi d'uso.

NotificationOptions.vibrate

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

Un pattern 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, con gli indici pari (0, 2, 4 e così via) che indicano la durata della vibrazione e gli indici dispari che 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 richiesta di funzionalità comune ancora presente da parte degli sviluppatori è la possibilità di chiudere una notifica dopo un determinato periodo di tempo o di inviare una notifica push con lo scopo di chiudere una notifica se è visibile.

Al momento non esiste un modo per farlo e non è previsto nelle specifiche :( ma il team tecnico di Chrome è a conoscenza di questo caso d'uso.

Notifiche Android

Sul 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 limitazioni della piattaforma: in particolare, Chrome non può supportare i callback sull'oggetto Notification, come onclick. Tuttavia, viene utilizzato su computer per visualizzare le notifiche per le app web che potresti avere aperte al momento.

L'unico motivo per cui lo menziono è che in origine un semplice rilevamento delle funzionalità come quello riportato di seguito ti aiutava a supportare il desktop e non causava 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 questo rilevamento delle funzionalità non è più appropriato. Se provi a creare una notifica su Chrome per Android, riceverai il seguente messaggio di errore:

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

Al momento, il modo migliore per rilevare le funzionalità per Android e computer è:

    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;
    }

Può essere utilizzato 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();
    }
.