먼저 제목이 너무 우스꽝스러워 죄송합니다.
Chrome 44에서는 Notfication.data와 ServiceWorkerRegistration.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();
}
사용 권장사항을 포함한 전체 문서를 확인하세요.