Powiadamianie o zmianach w powiadomieniach

Po pierwsze, przepraszam za ten okropny tytuł, ale nie udało mi się.

W Chrome 44 dodane i otwierają się Notfication.data i ServiceWorkerRegistration.getNotifications() / upraszczają niektóre typowe przypadki użycia związane z powiadomieniami w wiadomościach push.

Dane dotyczące powiadomień

Notification.data umożliwia powiązanie obiektu JavaScript z powiadomieniem.

Zasadniczo sprowadza się to do tego, że po otrzymaniu wiadomości push możesz utworzyć powiadomienie z pewnymi danymi, a potem jako zdarzenie powiadamiania kliknij powiadomienie, które zostało kliknięte, i pobierz jego dane.

Na przykład utworzenie obiektu danych i dodanie go do opcji powiadomień w ten sposób:

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

Oznacza to, że możemy uzyskać informacje dotyczące zdarzenia „powiadomienie”:

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

Wcześniej trzeba było przechowywać dane w IndexDB lub dodać coś na końcu adresu URL ikony.

ServiceWorkerRegistration.getNotifications()

Deweloperzy, którzy pracują nad powiadomieniami push, często proszą o większą kontrolę nad wyświetlanymi powiadomieniami.

Przykładem może być aplikacja do obsługi czatu, w której użytkownik wysyła wiele wiadomości, a odbiorca wyświetla wiele powiadomień. Najlepiej byłoby, gdyby aplikacja zauważyła, że masz kilka niewyświetlonych powiadomień, i zmieściła je w jednym powiadomieniu.

Bez metody getPowiadomienia() możesz zastąpić poprzednie powiadomienie najnowszą wiadomością. Funkcja getPowiadomienia() umożliwia „zwinięcie” powiadomień, jeśli jest ono już wyświetlane, co zwiększa komfort użytkowników.

Przykład grupowania powiadomień

Odpowiedni kod jest stosunkowo prosty. W zdarzeniu push użyj wywołania ServiceWorkerRegistration.getPowiadomienia(), aby uzyskać tablicę bieżących powiadomień i zdecydować, czy chcesz zwijać wszystkie powiadomienia czy użyć tagu 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);
    }));
    }
});

Pierwszą rzeczą, na jaką warto zwrócić uwagę w tym fragmencie kodu, jest to, że filtrujemy powiadomienia, przekazując obiekt filtra do getpowiadomień(). Oznacza to, że możemy uzyskać listę powiadomień dotyczących określonego tagu (w tym przykładzie dla określonej rozmowy).

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

Następnie przyglądamy się wszystkim powiadomieniom i sprawdzamy, czy jest z nimi powiązana liczba powiadomień oraz czy następuje wzrost. Dzięki temu, jeśli użytkownik zobaczy jedno powiadomienie o dwóch nieprzeczytanych wiadomościach, chcemy zwrócić uwagę, że po nadejściu nowej wiadomości push są 3 nieprzeczytane.

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

Aby mieć pewność, że powiadomienie zostało usunięte z listy powiadomień, musisz wywołać w powiadomieniu metodę close(). Jest to błąd w Chrome, ponieważ każde powiadomienie jest zastępowane kolejnym powiadomieniem, ponieważ używany jest ten sam tag. Obecnie to zastąpienie nie jest odzwierciedlane w zwróconej tablicy z getNotifications().

To tylko jeden z przykładów funkcji getPowiadomienia(). Jak łatwo sobie wyobrazić, ten interfejs API otwiera wiele innych zastosowań.

NotificationOptions.vibrate

Od Chrome 45 podczas tworzenia powiadomienia można określić wzór wibracji. Na urządzeniach obsługujących interfejs Vibration API (obecnie tylko Chrome na Androida) możesz dostosować wzór wibracji, który będzie używany podczas wyświetlania powiadomienia.

Wzór wibracji może mieć postać tablicy liczbowej lub pojedynczej liczby traktowanej jako tablica jednej liczby. Wartości w tablicy podają czas w milisekundach, gdzie indeksy parzyste (0, 2, 4, ...) to czas, po którym mają wibrować, a indeksy nieparzyste to czas postoju przed następną wibracją.

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

Pozostałe prośby o włączenie funkcji

Ostatnią częstą propozycją od deweloperów jest możliwość zamknięcia powiadomienia po upływie określonego czasu lub wysłania powiadomienia push w celu zamknięcia powiadomienia, jeśli jest widoczne.

Obecnie nie ma sposobu, aby to zrobić, a żadna specyfikacja nie na to pozwala :( ale zespół inżynierów Chrome wie o tym przypadku użycia.

Powiadomienia w Androidzie

Na komputerze możesz utworzyć powiadomienie, używając tego kodu:

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

Na Androidzie nigdy nie było to możliwe ze względu na ograniczenia platformy. W szczególności Chrome nie obsługuje wywołań zwrotnych znajdujących się w obiekcie powiadomienia, np. „onClick”. Jest on jednak używany na komputerze do wyświetlania powiadomień o otwartych obecnie aplikacjach internetowych.

Wspominam tylko, że proste wykrywanie funkcji (takie jak ta poniżej) pomoże Ci obsługiwać komputery i nie spowoduje żadnych błędów na Androidzie:

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

Jednak dzięki obsłudze powiadomień push w Chrome na Androida powiadomienia można tworzyć za pomocą obiektów ServiceWorker, ale nie na stronie internetowej, co oznacza, że ta funkcja nie jest już odpowiednia. Jeśli spróbujesz utworzyć powiadomienie w Chrome na Androida, zobaczysz ten komunikat o błędzie:

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

Najlepszym sposobem wykrywania funkcji w przypadku Androida i komputera jest wykonanie tych czynności:

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

Może on wyglądać tak:

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