Benachrichtigung bei Änderungen an Benachrichtigungen

Matt Gaunt

Zuerst möchte ich mich für diesen miesen Titel entschuldigen, aber ich konnte es nicht tun.

In Chrome 44 werden Notfication.data und ServiceWorkerRegistration.getNotifications() hinzugefügt. Dadurch werden einige gängige Anwendungsfälle beim Umgang mit Benachrichtigungen mit Push-Nachrichten geöffnet bzw. vereinfacht.

Benachrichtigungsdaten

Mit Notification.data können Sie ein JavaScript-Objekt mit einer Benachrichtigung verknüpfen.

Im Wesentlichen läuft das so ab: Wenn Sie eine Push-Nachricht erhalten, können Sie eine Benachrichtigung mit einigen Daten erstellen. Im Ereignis „benachrichtigungclick“ erhalten Sie dann die Benachrichtigung, auf die geklickt wurde, und die entsprechenden Daten.

Wenn Sie beispielsweise ein Datenobjekt erstellen und Ihren Benachrichtigungsoptionen hinzufügen, sehen Sie Folgendes:

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

Gibt an, dass wir die Informationen im Ereignis „notificationclick“ abrufen können:

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

Bisher mussten Daten in IndexDB verwahrt oder etwas an das Ende der Symbol-URL angehängt werden.

ServiceWorkerRegistration.getNotifications()

Eine häufige Anfrage von Entwicklern, die an Push-Benachrichtigungen arbeiten, besteht darin, mehr Kontrolle über die angezeigten Benachrichtigungen zu haben.

Ein Anwendungsbeispiel wäre eine Chatanwendung, in der ein Nutzer mehrere Nachrichten sendet und der Empfänger mehrere Benachrichtigungen anzeigt. Idealerweise würde die Web-App erkennen, dass mehrere Benachrichtigungen vorhanden sind, und diese in einer einzigen Benachrichtigung minimieren.

Ohne getNotifications() können Sie am besten die vorherige Benachrichtigung durch die neueste Nachricht ersetzen. Mit getNotifications() können Sie die Benachrichtigungen minimieren, wenn bereits eine Benachrichtigung angezeigt wird. Dies verbessert die Nutzererfahrung.

Beispiel für das Gruppieren von Benachrichtigungen

Der Code dafür ist relativ einfach. Rufen Sie innerhalb des Push-Ereignisses ServiceWorkerRegistration.getNotifications() auf, um ein Array aktueller Benachrichtigungen zu erhalten und von dort aus das richtige Verhalten festzulegen, sei es das Minimieren aller Benachrichtigungen oder die Verwendung von 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);
    }));
    }
});

Bei diesem Code-Snippet ist zunächst zu beachten, dass wir unsere Benachrichtigungen filtern, indem wir ein Filterobjekt an getNotifications() übergeben. Das bedeutet, dass wir eine Liste von Benachrichtigungen für ein bestimmtes Tag abrufen können (in diesem Beispiel für eine bestimmte Konversation).

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

Dann sehen wir uns die sichtbaren Benachrichtigungen an und kontrollieren, ob dieser Benachrichtigung eine bestimmte Anzahl zugeordnet ist, und erhöhen die Anzahl entsprechend. Wenn also eine Benachrichtigung vorhanden ist, die den Nutzer darüber informiert, dass es zwei ungelesene Nachrichten gibt, möchten wir darauf hinweisen, dass bei einem neuen Push drei ungelesene Nachrichten vorhanden sind.

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

Eine Feinheiten zu hervorheben ist, dass Sie close() für die Benachrichtigung aufrufen müssen, um sicherzustellen, dass die Benachrichtigung aus der Benachrichtigungsliste entfernt wird. Dies ist ein Fehler in Chrome, da jede Benachrichtigung durch die nächste ersetzt wird, da dasselbe Tag verwendet wird. Derzeit wird diese Ersetzung im zurückgegebenen Array von getNotifications() nicht widergespiegelt.

Dies ist nur ein Beispiel für getNotifications(). Wie Sie sich vorstellen können, bietet diese API eine Reihe weiterer Anwendungsfälle.

NotificationOptions.vibrate

Ab Chrome 45 können Sie beim Erstellen einer Benachrichtigung ein Vibrationsmuster festlegen. Auf Geräten, die die Vibration API unterstützen – derzeit nur Chrome für Android – können Sie auf diese Weise das Vibrationsmuster anpassen, das beim Anzeigen der Benachrichtigung verwendet wird.

Ein Vibrationsmuster kann entweder ein Array von Zahlen oder eine einzelne Zahl sein, die als Array mit einer Zahl behandelt wird. Die Werte im Array geben die Zeiten in Millisekunden an, wobei die geraden Indizes (0, 2, 4, ...) angeben, wie lange vibrieren soll, und die ungeraden Indizes angeben, wie lange vor der nächsten Vibration pausiert werden soll.

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

Übrige häufige Anfragen für Funktionen

Eine weitere häufige Funktionsanfrage von Entwicklern ist die Möglichkeit, eine Benachrichtigung nach einem bestimmten Zeitraum zu schließen, oder die Möglichkeit, eine Push-Benachrichtigung mit dem Zweck zu senden, nur eine Benachrichtigung zu schließen, sofern sie sichtbar ist.

Im Moment gibt es keine Möglichkeit, dies zu tun, und auch nichts in der Spezifikation erlaubt dies. Dieser Anwendungsfall ist jedoch dem Chrome-Entwicklerteam bekannt.

Android-Benachrichtigungen

Auf dem Desktop können Sie eine Benachrichtigung mit dem folgenden Code erstellen:

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

Dies wurde unter Android aufgrund von Plattformeinschränkungen nie unterstützt: Chrome unterstützt insbesondere Callbacks für das Benachrichtigungsobjekt wie "onclick" nicht. Sie wird jedoch auf dem Computer verwendet, um Benachrichtigungen für Web-Apps anzuzeigen, die Sie möglicherweise gerade geöffnet haben.

Der einzige Grund, warum ich es erwähne, ist, dass eine einfache Funktionserkennung wie die folgende ursprünglich dir bei der Desktop-Unterstützung helfen würde und unter Android keine Fehler verursachen würde:

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

Da Push-Benachrichtigungen jetzt in Chrome für Android unterstützt werden, können Benachrichtigungen jedoch von einem ServiceWorker, jedoch nicht von einer Webseite erstellt werden. Dies bedeutet, dass diese Erkennungsfunktion nicht mehr geeignet ist. Wenn Sie versuchen, eine Benachrichtigung in Chrome für Android zu erstellen, erhalten Sie diese Fehlermeldung:

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

So funktioniert die Funktionserkennung derzeit für Android und 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;
    }

Dies kann so verwendet werden:

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