原文地址:handling messageshtml
譯文地址:推送事件android
譯者:張卓git
到此已經覆蓋了訂閱用戶並給其推送發送消息。下一步是在用戶的設備上接收此推送消息並顯示通知(以及咱們可能要作的任何其餘工做)。web
當接受到一條消息時,一個推送事件將被 dispatch 到你的 service worker 中。chrome
監聽推送事件的代碼和在 JavaScript 中監聽其它事件的代碼十分相似:json
self.addEventListener('push', function(event) {
if (event.data) {
console.log('This push event has data: ', event.data.text());
} else {
console.log('This push event has no data.');
}
});
複製代碼
對於不熟悉 service workers 的開發者來講,這段代碼最奇怪的部分應該是變量 self
。self
經常使用在 Web Workers 中, service workers 就是這樣的。self
是指全局做用域,相似於瀏覽器環境中的 window
。但對於 web workers 和 service workers,self
指的的 worker 自己。windows
在上面的例子中,能夠將 self.addEventListener()
視爲向 service workers 自己添加事件監聽。api
在推送事件示例中,咱們檢查是否有數據,並打印一些日誌到終端。promise
除此以外,還有其餘方法能夠解析推送事件中的數據:
// 返回 string
event.data.text()
// Parses data as JSON string and returns an Object
event.data.json()
// 返回 blob
event.data.blob()
// 返回 arrayBuffer
event.data.arrayBuffer()
複製代碼
大多數人使用 json()
或者 text()
(取決於他們但願從應用程序那獲得什麼)。
此示例演示如何添加推送事件監聽器以及如何訪問數據,可是它 缺乏兩個很是重要的功能:它沒有顯示通知,而且沒有使用 event.waitUntil()
。
必需要了解的一點是,你幾乎沒法控制 service workers 的代碼什麼時候運行,瀏覽器決定什麼時候將其喚醒以及什麼時候終止它。惟一的方法是,你告訴瀏覽器:「嘿——我很是忙,要作重要的事情了」,將一個 promise 對象傳遞給 event.waitUntil()
方法,這樣,瀏覽器就會 保持 service workers 運行,直到傳入的 promise 被 resolve。
對於推送事件,還有一個必要條件是必須在 promise 被 resolve 以前顯示通知。
如下是顯示通知的基本示例:
self.addEventListener('push', function(event) {
const promiseChain = self.registration.showNotification('Hello, World.');
event.waitUntil(promiseChain);
});
複製代碼
執行 self.registration.showNotification()
方法會向用戶顯示一個通知而且返回一個 promise 對象,這個 promise 對象會在通知顯示以後被 resolve。
爲了讓這個例子儘量清楚,我已經將這個 promise 對象賦值給了一個 叫作 promiseChain
的變量,而後將其傳遞給 event.waitUntil()
。 我知道這裏 很是冗長,但我已經看到了許多由此引起的問題,例如, 誤解了應該傳遞給 waitUntil()
的內容,或者是一個錯誤的 promise 鏈。
一個包括網絡請求數據和分析追蹤推送事件的例子以下:
self.addEventListener('push', function(event) {
const analyticsPromise = pushReceivedTracking();
const pushInfoPromise = fetch('/api/get-more-data')
.then(function(response) {
return response.json();
})
.then(function(response) {
const title = response.data.userName + ' says...';
const message = response.data.message;
return self.registration.showNotification(title, {
body: message
});
});
const promiseChain = Promise.all([
analyticsPromise,
pushInfoPromise
]);
event.waitUntil(promiseChain);
});
複製代碼
這裏爲了示例,咱們調用一個返回 promise 對象的函數 pushReceivedTracking()
, ,僞裝將發出網絡請求到咱們的分析提供商。同時,咱們也會發送網絡請求、獲取響應,並使用響應的數據來顯示通知的標題和內容。
咱們使用 Promise.all()
將這兩個 promise 對象合併,來確保 service worker 在這兩個任務完成以前存活。合併後的 promise 被傳遞進 event.waitUntil()
,這意味着瀏覽器將等到兩個 promise 都完成後,纔會檢查通知已顯示,最後終止 service worker。
注意:若是你對 promise 鏈式調用有些疑惑,將功能分解爲函數會有助於下降複雜性,同時也推薦這篇Philip Walton 的博文來理解 promise 的鏈式調用。重點是你應該嘗試如何來寫 promise 以及它的鏈式調用,最終找到適合本身的風格。
咱們應該關注 waitUntil()
以及如何使用它,由於開發人員經常會面臨的一個問題是,當 promise 鏈使用的不正確時,Chrome 會 顯示此「默認」通知:
當接收到一個推送消息,但在 service worker 中的推送事件當傳遞給 event.waitUntil()
的 promise 結束以後也沒有顯示任何消息,Chrome 就只會顯示 "This site has been updated in the background."
致使這個問題主要緣由是開發者的代碼中常常在調用 self.registration.showNotification()
以後在 promise 中 沒有返回任何東西,這會致使顯示默認通知。舉個例子,咱們能夠刪除上面示例中的 self.registration.showNotification()
的返回值,就會有看到「默認」通知的風險。
self.addEventListener('push', function(event) {
const analyticsPromise = pushReceivedTracking();
const pushInfoPromise = fetch('/api/get-more-data')
.then(function(response) {
return response.json();
})
.then(function(response) {
const title = response.data.userName + ' says...';
const message = response.data.message;
self.registration.showNotification(title, {
body: message
});
});
const promiseChain = Promise.all([
analyticsPromise,
pushInfoPromise
]);
event.waitUntil(promiseChain);
});
複製代碼
你能夠看到它是如何容易遺漏的。
請記住 - 若是看到該通知,請檢查 promise 鏈和 event.waitUntil()
。
在下一節中,咱們將看看咱們能夠作什麼來設置通知的樣式以及能夠展現什麼內容。
譯文地址:顯示一個通知
譯者:劉文濤
我將通知參數分爲兩部分,一部分處理視覺(本節),另外一部分解釋通知的行爲。
這麼作的緣由是每一個開發人員都須要擔憂視覺方面,而行爲方面則取決於你使用推送的方式。
下面全部的例子的源代碼,都來自個人一個 demo 頁面。 若是你想本身測試它們,請點擊下面的按鈕。
顯示一個通知的 API 很簡單,以下:
<ServiceWorkerRegistration>.showNotification(<title>, <options>);
複製代碼
title 是一個字符串類型,options 的參數以下:
{
"//": "Visual Options",
"body": "<String>",
"icon": "<URL String>",
"image": "<URL String>",
"badge": "<URL String>",
"vibrate": "<Array of Integers>",
"sound": "<URL String>",
"dir": "<String of 'auto' | 'ltr' | 'rtl'>",
"//": "Behavioural Options",
"tag": "<String>",
"data": "<Anything>",
"requireInteraction": "<boolean>",
"renotify": "<Boolean>",
"silent": "<Boolean>",
"//": "Both Visual & Behavioural Options",
"actions": "<Array of Strings>",
"//": "Information Option. No visual affect.",
"timestamp": "<Long>"
}
複製代碼
首先讓咱們看看視覺相關的參數,以下圖:
title 和 body 參數,顧名思義,即通知上顯示的兩塊不一樣區域的文本(標題和文本)
若是咱們運行如下代碼:
const title = 'Simple Title';
const options = {
body: 'Simple piece of body text.\nSecond line of body text :)'
};
registration.showNotification(title, options);
複製代碼
咱們會在 chrome 中收到以下通知:
在 Linux 的 Firefox 上,它看起來是這樣的:
我很好奇,若是我添加了大量文本會發生什麼,其結果是:
有趣的是,Linux 上的 Firefox 截斷了正文的部分,直到鼠標 hover 到通知上面時,會展開顯示所有
我文中加入這些例子的緣由有2個。首先瀏覽器之間會有顯示上的差別。單單隻看文本,Firefox 和 Chrome 在顯示和行爲上有所不一樣。 其次是跨平臺存在差別。 Chrome 爲全部平臺提供自定義用戶界面,而 Linux 機器上的 Firefox 則使用系統通知。 相同的通知在 windows 上的 Firefox 顯示以下:
參數 icon
其實就是在標題和正文旁邊展現的一張小圖。
在你的代碼中,你只須要提供一個你想加載的圖片 URL。
const title = 'Icon Notification';
const options = {
icon: '/images/demos/icon-512x512.png'
};
registration.showNotification(title, options);
複製代碼
Linux 的 Chrome 上,咱們收到的通知以下:
Firefox:
悲傷的是,圖標大小並無固定標準。
Android彷佛想要一個64dp的圖像(這是設備像素比例的64倍)。
若是咱們假設設備的最高像素比例爲3,那麼192像素及以上大小的圖片是安全的。
注意:某些瀏覽器可能須要HTTPS協議頭的圖像。 若是你打算使用第三方圖像,請注意這一點。
badge
是一個小的單色圖標,用於向用戶展現更多信息,告知用戶消息是從哪裏來的。
const title = 'Badge Notification';
const options = {
badge: '/images/demos/badge-128x128.png'
};
registration.showNotification(title, options);
複製代碼
在寫本文時,badge 僅適用於 Android 版 Chrome。
在其餘瀏覽器(或沒有指定 badge 的 Chrome)上,你會看到瀏覽器的圖標。
與 icon 參數同樣,這裏沒有關於使用什麼尺寸的 實際標準。
經過參考 Android guidelines,建議的大小是24px乘以設備像素比例。
也就是說使用大於72px大小的圖片應該是合適的(假設設備的最大像素比率爲3)。
image
參數可用於向用戶展現較大的圖片。尤爲適合展現預覽圖。
const title = 'Image Notification';
const options = {
image: '/images/demos/unsplash-farzad-nazifi-1600x1100.jpg'
};
registration.showNotification(title, options);
複製代碼
在系統桌面上,通知顯示樣式以下:
在Android上,圖片展現的 裁剪方式和顯示的比例是不一樣的,以下圖:
鑑於桌面和移動設備之間的圖片顯示比例差別,給一個標準是極其困難的。
如上圖所示,桌面版 Chrome 中,並未徹底填充,空間比例爲4:3,也許最好的方法是以此比例設置圖片,並容許 Android 裁剪圖片。 話雖然是這樣說,image 參數 還是一個新的屬性,顯示的形式是可能會改變的。
在 Android 上,我能找到的惟一的標準寬度是450dp。
基於這個標準,寬度爲1350px或更高的圖像將是一個不錯的選擇(假設設備的最大像素比率爲3)。
你能夠定義 actions
,來顯示帶按鈕的通知。
const title = 'Actions Notification';
const options = {
actions: [
{
action: 'coffee-action',
title: 'Coffee',
icon: '/images/demos/action-1-128x128.png'
},
{
action: 'doughnut-action',
title: 'Doughnut',
icon: '/images/demos/action-2-128x128.png'
},
{
action: 'gramophone-action',
title: 'gramophone',
icon: '/images/demos/action-3-128x128.png'
},
{
action: 'atom-action',
title: 'Atom',
icon: '/images/demos/action-4-128x128.png'
}
]
};
const maxVisibleActions = Notification.maxActions;
if (maxVisibleActions < 4) {
options.body = `This notification will only display ` +
`${maxVisibleActions} actions.`;
} else {
options.body = `This notification can display up to ` +
`${maxVisibleActions} actions.`;
}
registration.showNotification(title, options);
複製代碼
目前只有 Chrome 和 Android 中的 Opera 支持 actions 參數。
對於每一個 action,你能夠定義一個 title,一個「action」(即一個 ID)和一個圖標。標題和圖標是你能夠在通知中看到的內容。ID 是用來檢測操做按鈕是否已經被點擊過(咱們將在下一節中更詳細地介紹這一點)。
在上面的示例中,我定義了 4 個 actions,來證實你能夠定義比顯示的 actions 更多的 actions。 若是你想知道瀏覽器能夠顯示多少個 action 按鈕,你能夠查看演示正文中使用的 Notification.maxActions
。
在桌面端上,操做按鈕圖標會顯示自己的顏色(請參閱上面的粉色甜甜圈 icon)。
在 Android 6.0 Marshmallow 上,圖標被改變顏色以匹配系統配色方案:
Chrome 將有望改變在桌面端的行爲 ,與 Android 相匹配(即應用適當的配色方案使圖標與系統配色相匹配)。同時,你能夠手動修改圖標顏色爲"#333333",來匹配 Chrome 的文字顏色。
在 Android 7.0 Nougat 上,action 圖標是根本不顯示的。
值得一提的是,這些圖標在 Android 上看起來很清晰,但在桌面上看起來不那麼清晰。
在桌面版 Chrome 上使用的最佳尺寸是24px x 24px。 惋惜這個在 Android 上看起來不合適。
因此,咱們能夠從這些差別中得出最佳實踐:
Notification 規範正在探索一種能夠定義多種尺寸圖標的方式,但彷佛到最終達成共識以前仍是須要一些時間。
「dir」參數容許你定義文本顯示的方向:從右到左或從左到右。
在測試中,顯示的方向彷佛很大程度上取決於文本,而不是這個參數。根據規範,這個參數用於建議瀏覽器如何顯示文本(如同 actions 中的參數),可是並無什麼用。
若是須要定義文字方向的話,最好定義一下,不然瀏覽器可能會根據提供的文本按照默認的方式顯示。
該參數應能夠設置爲:auto
,ltr
或rtl
。
RTL(從右向左)語言在 Linux 的 Chrome 上顯示以下:
在 Firefox 上(當鼠標懸停在上面時),你會獲得的顯示以下:
假設用戶設備當前設置容許振動(即設備不處於靜音模式),vibrate 參數可讓你顯示一條通知的時候,使用振動模式。
vibrate 參數的格式是一組數字,用於描述設備應該振動的毫秒數,後面跟着設備不該該振動的毫秒數。
const title = 'Vibrate Notification';
const options = {
// Star Wars shamelessly taken from the awesome Peter Beverloo
// https://tests.peter.sh/notification-generator/
vibrate: [500,110,500,110,450,110,200,110,170,40,450,110,200,110,170,40,500]
};
registration.showNotification(title, options);
複製代碼
該參數只對支持振動的設備有做用。
sound 參數容許你定義一個音頻,在收到通知時能夠播放。
在寫本文時,沒有瀏覽器支持這個參數。
const title = 'Sound Notification';
const options = {
sound: '/demos/notification-examples/audio/notification-sound.mp3'
};
registration.showNotification(title, options);
複製代碼
Timestamp 參數用於告訴平臺觸發推送消息事件的時間。
timestamp
參數 是從00:00:00,即1970年1月1日(即 unix 時間)開始的毫秒數。
const title = 'Timestamp Notification';
const options = {
body: 'Timestamp is set to "01 Jan 2000 00:00:00".',
timestamp: Date.parse('01 Jan 2000 00:00:00')
};
registration.showNotification(title, options);
複製代碼
在通知中,信息的顯示缺少獨特性是我所見最失敗的用戶體驗。
首先你應該考慮爲何要推送這個通知,而且確保全部的通知參數都能幫助用戶理解爲何他們須要閱讀這個通知。
看例子很容易,你會以爲「我永遠不會犯這個錯」,可是掉入這個陷阱比你想象的要更容易。
下面是一些咱們須要避免的常見陷阱
在寫本文時,Chrome 和 Firefox 在通知功能支持方面存在很大差別。
幸運的是,你能夠經過查看 Notification 原型來檢測瀏覽器對通知功能的支持。
若是咱們想知道通知是否支持操做按鈕,咱們會執行如下操做:
if ('actions' in Notification.prototype) {
// Action buttons are supported.
} else {
// Action buttons are NOT supported.
}
複製代碼
有了這個,咱們能夠更改咱們向用戶展現的通知。
使用其餘參數,只需執行與上面相同的方法,將 「actions」 替換爲所需的參數名稱。