首先,很抱歉造成這個困擾,但實在不行。
在 Chrome 44 中,我們新增了 Notfication.data 和 ServiceWorkerRegistration.getNotifications(),以及開啟 / 簡化處理含有推送訊息的通知時的一些常見用途。
通知資料
Notification.data 可讓您將 JavaScript 物件與通知建立關聯。
基本上,當你收到推送訊息時,可以建立含有部分資料的通知,然後在通知點擊事件中取得點選的通知,並取得資料。
例如,建立資料物件並新增至通知選項,如下所示:
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
})
);
});
意義:我們可在通知點擊事件中取得資訊:
self.addEventListener('notificationclick', function(event) {
var doge = event.notification.data.doge;
console.log(doge.wow);
});
在此之前,您必須將資料存放在 IndexDB 中,或是在圖示網址結尾放置其他內容。請見。
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)
接著,我們會查看可見的通知,並確認是否有與通知相關聯的通知計數,並據此遞增。這麼一來,如果有一則通知告知使用者有兩則未讀訊息,我們就會指出當新的推送傳入時,有三則未讀訊息。
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 的裝置上 (目前僅支援 Chrome for Android),可讓您自訂顯示通知時使用的震動模式。
震動模式可以是一串數字,也可以是視為單一數字陣列的單一數字。陣列中的值以毫秒為單位表示,偶數 (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 不支援 Notification 物件的回呼,例如 click。但會在電腦上顯示目前開啟的網頁應用程式通知。
我只提及,只是這個簡單的功能偵測功能 (如下例所示) 可協助您支援電腦,而不會在 Android 上產生任何錯誤:
if (!'Notification' in window) {
// Notifications aren't supported
return;
}
不過,有了 Chrome for Android 的推播通知支援,您可以透過 ServiceWorker 建立通知,但無法透過網頁建立通知,這表示這項功能偵測不再適用。如果您嘗試在 Chrome for Android 版中建立通知,您會收到以下錯誤訊息:
_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();
}