알림 변경사항 알림

먼저 제목이 너무 우스꽝스러워 죄송합니다.

Chrome 44에서는 Notfication.dataServiceWorkerRegistration.getNotifications()가 추가되어 푸시 메시지로 알림을 처리할 때 일반적인 사용 사례가 열리고 이를 단순화합니다.

알림 데이터

Notification.data를 사용하면 JavaScript 객체를 Notification과 연결할 수 있습니다.

기본적으로 푸시 메시지를 수신하면 일부 데이터가 포함된 알림을 만들 수 있으며, notificationclick 이벤트에서 클릭된 알림을 가져와 데이터를 가져올 수 있습니다.

예를 들어 다음과 같이 데이터 객체를 만들어 알림 옵션에 추가합니다.

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

즉, notificationclick 이벤트에서 정보를 가져올 수 있습니다.

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

이전에는 IndexDB에 데이터를 보관하거나 아이콘 URL 끝에 무언가를 추가해야 했습니다.

ServiceWorkerRegistration.getNotifications()

푸시 알림을 사용하는 개발자가 자주 요청하는 기능 중 하나는 표시되는 알림을 더 효과적으로 제어하는 기능입니다.

사용자가 여러 메시지를 전송하고 수신자가 여러 알림을 표시하는 채팅 애플리케이션을 예로 들 수 있습니다. 이상적으로 웹 앱에서는 조회되지 않은 알림이 여러 개 있음을 확인하고 알림을 단일 알림으로 축소할 수 있습니다.

getNotifications()가 없으면 이전 알림을 최신 메시지로 바꾸는 것이 가장 좋습니다. getNotifications()를 사용하면 알림이 이미 표시된 경우 알림을 '축소'하여 훨씬 더 나은 사용자 환경을 제공할 수 있습니다.

알림을 그룹화하는 예시

이를 위한 코드는 비교적 간단합니다. 푸시 이벤트 내에서 ServiceWorkerRegistration.getNotifications()를 호출하여 현재 알림 배열을 가져오고, 거기서부터 올바른 동작(모든 알림 접기 또는 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);
    }));
    }
});

이 코드 스니펫에서 가장 먼저 강조할 점은 getNotifications()에 필터 객체를 전달하여 알림을 필터링한다는 것입니다. 즉, 특정 태그 (이 예에서는 특정 대화)의 알림 목록을 가져올 수 있습니다.

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

그런 다음 표시되는 알림을 살펴보고 이 알림과 연결된 알림 수가 있는지 확인하고 이를 기반으로 증가합니다. 이렇게 하면 사용자에게 읽지 않은 메시지가 2개 있음을 알리는 알림이 하나 있는 경우 새 푸시가 도착할 때 읽지 않은 메시지가 3개 있음을 표시할 수 있습니다.

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

알림이 알림 목록에서 삭제되도록 하려면 알림에서 close()를 호출해야 합니다. 동일한 태그가 사용되므로 각 알림이 다음 알림으로 대체되므로 이는 Chrome의 버그입니다. 현재 이 대체는 getNotifications()에서 반환된 배열에 반영되지 않습니다.

이것은 getNotifications()의 한 예일 뿐이며, 예상한 것처럼 이 API는 다양한 사용 사례를 열어줍니다.

NotificationOptions.vibrate

Chrome 45부터 알림을 만들 때 진동 패턴을 지정할 수 있습니다. Vibration API를 지원하는 기기(현재 Android용 Chrome만 해당)에서는 알림이 표시될 때 사용될 진동 패턴을 맞춤설정할 수 있습니다.

진동 패턴은 숫자 배열이거나 단일 숫자일 수 있으며, 이 경우 단일 숫자 배열로 취급됩니다. 배열의 값은 밀리초 단위의 시간을 나타내며 짝수 색인 (0, 2, 4, ...)은 진동 시간, 홀수 색인은 다음 진동 전에 일시중지할 시간을 나타냅니다.

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

나머지 일반 기능 요청

개발자의 남은 일반적인 기능 요청은 특정 시간 후에 알림을 닫는 기능 또는 알림이 표시되는 경우 알림을 닫는 목적으로 푸시 알림을 보내는 기능입니다.

현재로서는 이렇게 할 수 있는 방법이 없으며 사양을 허용하는 사양도 없습니다. 하지만 Chrome 엔지니어링팀은 이 사용 사례를 알고 있습니다.

Android 알림

데스크톱에서는 다음 코드로 알림을 만들 수 있습니다.

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

이는 플랫폼의 제한으로 인해 Android에서 지원되지 않았습니다. 특히 Chrome은 onclick과 같은 Notification 객체의 콜백을 지원할 수 없습니다. 하지만 데스크톱에서는 현재 열려 있을 수 있는 웹 앱의 알림을 표시하는 데 사용됩니다.

이 문제를 언급하는 유일한 이유는 원래 아래와 같은 간단한 기능 감지가 데스크톱을 지원하고 Android에서 오류를 일으키지 않는 데 도움이 되기 때문입니다.

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

하지만 이제 Android용 Chrome에서 푸시 알림이 지원되므로 ServiceWorker에서는 알림을 만들 수 있지만 웹페이지에서는 만들 수 없습니다. 즉, 이 기능 감지는 더 이상 적절하지 않습니다. Android용 Chrome에서 알림을 만들려고 하면 다음 오류 메시지가 표시됩니다.

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

현재 Android 및 데스크톱에서 기능을 감지하는 가장 좋은 방법은 다음을 실행하는 것입니다.

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

다음과 같이 사용할 수 있습니다.

    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();
    }
사용 권장사항을 포함한 전체 문서를 확인하세요.