Notification des modifications apportées aux notifications

Matt Gaunt

Tout d'abord, je vous prie de m'excuser pour ce titre horrible, mais je n'ai pas pu.

Dans Chrome 44, Notfication.data et ServiceWorkerRegistration.getNotifications() sont ajoutés et ouvrent / simplifient certains cas d'utilisation courants liés au traitement de notifications avec des messages push.

Données des notifications

Notification.data vous permet d'associer un objet JavaScript à une notification.

En résumé, lorsque vous recevez un message push, vous pouvez créer une notification avec des données, puis, dans l'événement notificationclick, vous pouvez obtenir la notification sur laquelle l'utilisateur a cliqué et obtenir ses données.

Par exemple, vous pouvez créer un objet de données et l'ajouter à vos options de notification comme suit:

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

Cela signifie que nous pouvons obtenir les informations dans l'événement notificationclick:

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

Auparavant, vous deviez stocker des données dans IndexDB ou ajouter quelque chose à la fin de l'URL de l'icône - eek.

ServiceWorkerRegistration.getNotifications()

Les développeurs travaillant sur les notifications push souhaitent souvent mieux contrôler les notifications qu'ils affichent.

Prenons l'exemple d'une application de chat dans laquelle un utilisateur envoie plusieurs messages et où le destinataire affiche plusieurs notifications. Idéalement, l'application Web devrait pouvoir remarquer que plusieurs notifications n'ont pas été vues et les réduire en une seule notification.

Sans getNotifications(), la meilleure solution est de remplacer la notification précédente par le dernier message. Avec getNotifications(), vous pouvez "réduire" les notifications si une notification est déjà affichée, ce qui améliore l'expérience utilisateur.

Exemple de regroupement des notifications.

Le code permettant d'effectuer cette opération est relativement simple. Dans votre événement push, appelez ServiceWorkerRegistration.getNotifications() pour obtenir un tableau des notifications actuelles, puis décidez du comportement approprié, qu'il s'agisse de réduire toutes les notifications ou d'utiliser la balise 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 première chose à mettre en évidence avec cet extrait de code est que nous filtrons nos notifications en transmettant un objet de filtre à getNotifications(). Cela signifie que nous pouvons obtenir une liste de notifications pour une balise spécifique (dans cet exemple pour une conversation particulière).

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

Nous examinons ensuite les notifications visibles et vérifions si un nombre de notifications est associé à cette notification, puis nous incrémentons en conséquence. De cette façon, si l'utilisateur reçoit une notification indiquant que deux messages n'ont pas été lus, il convient de signaler qu'il y a trois messages non lus à la réception d'un nouveau message 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();
}

Notez que vous devez appeler close() au niveau de la notification pour vous assurer que celle-ci est supprimée de la liste des notifications. Il s'agit d'un bug dans Chrome, car chaque notification est remplacée par la suivante, car la même balise est utilisée. Pour le moment, ce remplacement n'est pas reflété dans le tableau renvoyé par getNotifications().

Il ne s'agit là que d'un exemple de getNotifications() et, comme vous pouvez l'imaginer, cette API ouvre un éventail d'autres cas d'utilisation.

NotificationOptions.vibrate

À partir de Chrome 45, vous pouvez spécifier un motif de vibration lorsque vous créez une notification. Sur les appareils compatibles avec l'API Vibration (uniquement pour Chrome pour Android actuellement), cette option vous permet de personnaliser le motif du vibreur utilisé lors de l'affichage de la notification.

Un motif de vibration peut être un tableau de nombres ou un nombre unique traité comme un tableau d'un nombre. Les valeurs du tableau représentent les temps en millisecondes, les indices pairs (0, 2, 4, ...) correspondant à la durée de vibration et les indices impairs à la durée de la pause avant la vibration suivante.

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

Demandes de fonctionnalités courantes restantes

Une autre demande de fonctionnalité courante des développeurs est la possibilité de fermer une notification après un certain temps ou d'envoyer une notification push dans le but de fermer une notification si elle est visible.

Pour le moment, il n'existe aucun moyen de procéder, et rien dans les spécifications ne le permet. Toutefois, l'équipe d'ingénieurs Chrome est au courant de ce cas d'utilisation.

Notifications Android

Sur ordinateur, vous pouvez créer une notification avec le code suivant:

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

Cela n'a jamais été pris en charge sur Android en raison des restrictions de la plate-forme : en particulier, Chrome n'est pas compatible avec les rappels de l'objet Notification, comme par exemple. Mais il est utilisé sur ordinateur pour afficher des notifications pour les applications Web que vous avez peut-être actuellement ouvertes.

La seule raison pour laquelle je le mentionne est qu'à l'origine, une simple détection de fonctionnalités comme celle indiquée ci-dessous vous aiderait à prendre en charge les ordinateurs de bureau sans provoquer d'erreurs sur Android:

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

Toutefois, étant donné que les notifications push sont désormais compatibles avec Chrome pour Android, il est possible de créer des notifications à partir d'un ServiceWorker, mais pas d'une page Web, ce qui signifie que la détection de cette fonctionnalité n'est plus appropriée. Si vous essayez de créer une notification dans Chrome pour Android, le message d'erreur suivant s'affiche:

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

À l'heure actuelle, le meilleur moyen de détecter les fonctionnalités sur Android et sur ordinateur consiste à procéder comme suit:

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

Cela peut être utilisé comme ceci:

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