原文地址: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” 替换为所需的参数名称。