如果您询问开发者网络中缺少哪些移动设备功能,推送通知始终位居答案前列。
借助推送通知,您的用户可以选择及时接收他们喜爱的网站的最新动态,还可以利用具有吸引力的定制内容有效地重新吸引用户。
从 Chrome 42 版开始,Push API 和 Notification API 可供开发者使用。
Chrome 中的 Push API 依赖于一些不同的技术,包括 Web 应用清单和 Service Worker。在这篇博文中,我们将介绍所有这些技术,但仅为启动并运行推送消息传递的最低要求。如需更好地了解清单的一些其他功能以及 Service Worker 的离线功能,请点击上面的链接。
此外,我们还将介绍未来 Chrome 版本中会添加到该 API 的内容,最后会提供一个常见问题解答。
为 Chrome 实现推送消息
本部分介绍了为了在 Web 应用中支持推送消息传递需要完成的各个步骤。
注册 Service Worker
通过 Service Worker 实现 Web 推送消息存在一个依赖关系。这是因为收到推送消息时,浏览器可以启动一个无需打开页面就在后台运行的 Service Worker,并分派事件,以便您决定如何处理该推送消息。
以下示例展示了如何在 Web 应用中注册 Service Worker。当注册成功完成后,我们会调用 initialiseState(),我们稍后将介绍此内容。
var isPushEnabled = false;
…
window.addEventListener('load', function() {
var pushButton = document.querySelector('.js-push-button');
pushButton.addEventListener('click', function() {
if (isPushEnabled) {
unsubscribe();
} else {
subscribe();
}
});
// Check that service workers are supported, if so, progressively
// enhance and add push messaging support, otherwise continue without it.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(initialiseState);
} else {
console.warn('Service workers aren\'t supported in this browser.');
}
});
按钮点击处理程序为用户订阅或退订推送消息。isPushEnabled 是一个全局变量,仅跟踪推送消息当前是否已订阅。这些代码段将在整个代码段中引用。
然后,我们会在注册 service-worker.js
文件(具有处理推送消息的逻辑)之前检查 Service Worker 是否受支持。在这里,我们直接告知浏览器此 JavaScript 文件是网站的 Service Worker。
设置初始状态
![Chrome 中已启用和已停用推送消息的用户体验示例。](https://developer.chrome.google.cn/static/blog/push-notifications-on-the-open-web/image/example-enabled-disable-96d405ef6b25c.png?authuser=7&hl=zh-cn)
注册 Service Worker 后,我们需要设置界面的状态。
用户希望通过一个简单的界面为您的网站启用或停用推送消息,并且希望界面能及时反映任何变化。换句话说,如果它们为您的网站启用了推送消息,并在一周后退出,那么界面应突出显示推送消息已启用。
您可以在此文档中找到一些用户体验指南,在本文中,我们将重点介绍技术方面。
这时,您可能认为只有两种状态需要处理,即启用或停用。不过,您需要考虑通知周围的其他一些状态。
![一张示意图,突出显示了 Chrome 中推送的不同注意事项和状态](https://developer.chrome.google.cn/static/blog/push-notifications-on-the-open-web/image/a-diagram-highlighting-d-1738cfdc77ac4.png?authuser=7&hl=zh-cn)
在启用按钮之前,我们需要检查许多 API,如果一切都受支持,我们可以启用界面并设置初始状态来指示是否已订阅推送消息。
由于大多数此类检查都会导致界面被停用,因此您应将初始状态设置为“已停用”。如果网页的 JavaScript 存在问题(例如 JS 文件无法下载或用户已停用 JavaScript),这也可以避免混淆。
<button class="js-push-button" disabled>
Enable Push Messages
</button>
使用此初始状态,我们可以在 initialiseState()
方法中(即在注册 Service Worker 之后)执行上述检查。
// Once the service worker is registered set the initial state
function initialiseState() {
// Are Notifications supported in the service worker?
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
console.warn('Notifications aren\'t supported.');
return;
}
// Check the current Notification permission.
// If its denied, it's a permanent block until the
// user changes the permission
if (Notification.permission === 'denied') {
console.warn('The user has blocked notifications.');
return;
}
// Check if push messaging is supported
if (!('PushManager' in window)) {
console.warn('Push messaging isn\'t supported.');
return;
}
// We need the service worker registration to check for a subscription
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
// Do we already have a push message subscription?
serviceWorkerRegistration.pushManager.getSubscription()
.then(function(subscription) {
// Enable any UI which subscribes / unsubscribes from
// push messages.
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = false;
if (!subscription) {
// We aren't subscribed to push, so set UI
// to allow the user to enable push
return;
}
// Keep your server in sync with the latest subscriptionId
sendSubscriptionToServer(subscription);
// Set your UI to show they have subscribed for
// push messages
pushButton.textContent = 'Disable Push Messages';
isPushEnabled = true;
})
.catch(function(err) {
console.warn('Error during getSubscription()', err);
});
});
}
这些步骤的简要概述:
- 我们会检查 ServiceWorkerRegistration 原型中是否提供
showNotification
。如果没有它,我们将无法在收到推送消息时显示来自 Service Worker 的通知。 - 我们会检查当前的
Notification.permission
,以确保它不是"denied"
。权限遭拒意味着您无法显示通知,除非用户在浏览器中手动更改权限。 - 如需检查是否支持推送消息传递,我们需要检查窗口对象中是否有
PushManager
。 - 最后,我们使用
pushManager.getSubscription()
检查是否已有订阅。如果是,我们会将订阅详情发送到我们的服务器,以确保我们拥有正确的信息,并设置界面以指明推送消息功能已启用或未启用。我们将在本文的后面部分介绍订阅对象中存在哪些详细信息。
我们等到 navigator.serviceWorker.ready
解析完成后再检查订阅并启用推送按钮,因为只有在 Service Worker 处于活动状态后,您才可以实际订阅推送消息。
下一步是处理用户想要启用推送消息的情况,但在此之前,我们需要设置一个 Google Developer Console 项目并向清单添加一些参数,以便使用 Firebase Cloud Messaging (FCM)(以前称为 Google Cloud Messaging (GCM))。
在 Firebase 开发者控制台上创建项目
Chrome 使用 FCM 处理推送消息的发送和传递;不过,如需使用 FCM API,您需要在 Firebase Developer Console 上设置一个项目。
以下步骤仅适用于使用 FCM 的 Chrome、Android 版 Opera 和三星浏览器。我们将在本文的后面部分讨论该方法在其他浏览器中是如何工作的。
创建新的 Firebase 开发者项目
首先,您需要在 https://console.firebase.google.com/ 上点击“新建项目”来创建一个新项目。
添加项目名称并创建项目,系统会将您转到项目信息中心:
在此信息中心内,点击左上角的项目名称旁边的齿轮图标,然后点击“项目设置”。
在设置页面中,点击“Cloud Messaging”标签页。
此页面包含用于推送消息的 API 密钥(稍后将用到),以及我们需要在下一部分的 Web 应用清单中添加的发送者 ID。
添加 Web 应用清单
对于推送,我们需要添加一个带有 gcm_sender_id 字段的清单文件,以确保推送订阅成功。只有 Chrome、适用于 Android 的 Opera 和三星浏览器才需要此参数,以便它们可以使用 FCM / GCM。
这些浏览器在通过 FCM 为用户设备订阅订阅时,会使用 gcm_sender_id。这意味着 FCM 可以识别用户的设备,确保您的发送者 ID 与相应 API 密钥匹配,并且用户已允许您的服务器向他们发送推送消息。
下面是一个超级简单的清单文件:
{
"name": "Push Demo",
"short_name": "Push Demo",
"icons": [{
"src": "images/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}],
"start_url": "/index.html?homescreen=1",
"display": "standalone",
"gcm_sender_id": "<Your Sender ID Here>"
}
您需要将 gcm_sender_id 值设置为 Firebase 项目中的发送者 ID。
将清单文件保存到项目中(manifest.json 是一个好名称)后,请通过 HTML 引用该文件,并在网页标头中使用以下标记。
<link rel="manifest" href="/manifest.json">
如果您不添加包含这些参数的网页清单,则当您尝试订阅用户推送消息时,将会发生异常,并显示错误 "Registration failed - no sender id provided"
或 "Registration failed -
permission denied"
。
订阅推送消息
现在您已经设置了清单,可以返回到网站的 JavaScript 了。
若要进行订阅,您必须对 PushManager 对象调用 subscribe() 方法,该对象可通过 ServiceWorkerRegistration 访问。
这将要求用户向您的来源授予发送推送通知的权限。如果没有此权限,您将无法成功订阅。
如果解析 subscribe() 方法返回的 promise,您将获得一个 PushSubscription 对象,该对象将包含一个端点。
您应该将每个用户的端点保存在服务器上,因为稍后您需要他们发送推送消息。
以下代码可为用户订阅推送消息功能:
function subscribe() {
// Disable the button so it can't be changed while
// we process the permission request
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = true;
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function(subscription) {
// The subscription was successful
isPushEnabled = true;
pushButton.textContent = 'Disable Push Messages';
pushButton.disabled = false;
// TODO: Send the subscription.endpoint to your server
// and save it to send a push message at a later date
return sendSubscriptionToServer(subscription);
})
.catch(function(e) {
if (Notification.permission === 'denied') {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
console.warn('Permission for Notifications was denied');
pushButton.disabled = true;
} else {
// A problem occurred with the subscription; common reasons
// include network errors, and lacking gcm_sender_id and/or
// gcm_user_visible_only in the manifest.
console.error('Unable to subscribe to push.', e);
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
}
});
});
}
此时,您的 Web 应用已准备好接收推送消息,但在我们将推送事件监听器添加到 Service Worker 文件之前,什么都不会发生。
Service Worker 推送事件监听器
收到推送消息时(我们将在下一部分中介绍如何实际发送推送消息),您的 Service Worker 中会分派推送事件,此时您需要显示一条通知。
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';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
});
此代码可注册推送事件监听器,并显示带有预定义标题、正文、图标和通知标记的通知。此示例中有一点要强调的细节是 event.waitUntil()
方法。此方法接受 promise 并延长事件处理程序(也可以视为使 Service Worker 保持活动状态)的生命周期,直到 promise 得到解决;在这种情况下,传递给 event.waitUntil
的 promise 是从 showNotification()
返回的 Promise。
通知标记充当唯一通知的标识符。如果我们向同一端点发送了两条推送消息,两者之间的延迟较短,那么当显示带有相同标记的通知时,浏览器会显示第一条通知,并在收到推送消息时将其替换为第二条通知。
如果您想一次显示多个通知,请使用其他标记或根本不使用标记。 我们稍后会在本文中了解显示通知的更完整示例。现在,为简单起见,我们看看发送推送消息是否会显示此通知。
发送推送消息
我们已订阅推送消息,我们的 Service Worker 已准备好显示通知,是时候通过 FCM 发送推送消息了。
这仅适用于使用 FCM 的浏览器。
当您将 PushSubscription.endpoint
变量发送到您的服务器时,FCM 的端点是一个特殊的端点。它的网址末尾有一个参数,它是 registration_id
。
示例端点如下所示:
https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP
FCM 网址为:
https://fcm.googleapis.com/fcm/send
registration_id
为:
APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP
这仅适用于使用 FCM 的浏览器。在普通浏览器中,您只需获取一个端点,并以标准方式调用该端点,并且无论网址如何,它都会正常工作。
这意味着,您需要在自己的服务器上检查端点是否为 FCM,如果是,则提取 registration_id。要在 Python 中执行此操作,您可以执行如下操作:
if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
endpointParts = endpoint.split('/')
registrationId = endpointParts[len(endpointParts) - 1]
endpoint = 'https://fcm.googleapis.com/fcm/send'
获取注册 ID 后,即可调用 FCM API。您可以在此处找到 FCM API 参考文档。
调用 FCM 时,请注意以下几个重要方面:
- 调用 API 时,必须设置值为
key=<YOUR_API_KEY>
的 Authorization 标头,其中<YOUR_API_KEY>
是 Firebase 项目中的 API 密钥。- FCM 使用该 API 密钥来查找相应的发送者 ID,确保用户已授予您的项目权限,并最终确保服务器的 IP 地址已列入该项目的许可名单。
application/json
或application/x-www-form-urlencoded;charset=UTF-8
的相应Content-Type
标头,具体取决于您是以 JSON 数据还是表单数据形式发送数据。- 一组
registration_ids
- 这些是您从用户的端点中提取的注册 ID。
请务必查看相关文档,了解如何从服务器发送推送消息,但如需快速查看 Service Worker,您可以使用 cURL 向浏览器发送推送消息。
请用您自己的命令替换此 c网址 命令中的 <YOUR_API_KEY>
和 <YOUR_REGISTRATION_ID>
,然后从终端运行该命令。
您应该会看到一条出色的通知:
curl --header "Authorization: key=<YOUR_API_KEY>" --header
"Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
"{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
![来自 Android 版 Chrome 的推送消息示例。](https://developer.chrome.google.cn/static/blog/push-notifications-on-the-open-web/image/example-a-push-message-40a45aaa8288a.gif?authuser=7&hl=zh-cn)
在开发后端逻辑时,请记住 POST 正文的授权标头和格式特定于 FCM 端点,因此请检测端点何时用于 FCM,并有条件地添加标头并设置 POST 正文的格式。对于其他浏览器(以后可能是 Chrome),您需要实现网络推送协议。
在 Chrome 中当前实现的 Push API 有一个缺点,那就是您无法使用推送消息发送任何数据。不,什么都没有。这样做的原因是,在未来的实现中,必须先在服务器上对载荷数据进行加密,然后再将其发送到推送消息端点。这样,无论端点为哪种推送提供程序,都将无法轻松查看推送消息的内容。这还可以防范其他漏洞,例如 HTTPS 证书验证不当以及服务器与推送提供程序之间遭受中间人攻击。不过,这种加密目前尚不受支持,因此您需要执行提取操作,以获取填充通知所需的信息。
更完整的推送事件示例
到目前为止,我们看到的通知都相当基础,就示例而言,它在涵盖实际用例方面表现很差。
实际上,大多数人都希望在显示通知之前从其服务器获取一些信息。这可以是用特定内容填充通知标题和消息的数据,也可以更进一步,缓存某些页面或数据,以便在用户点击通知时,所有内容都可以在浏览器打开时立即提供,即使当时网络不可用也是如此。
在以下代码中,我们从 API 提取一些数据,将响应转换为对象,并使用它来填充通知。
self.addEventListener('push', function(event) {
// Since there is no payload data with the first version
// of push messages, we'll grab some data from
// an API and use it to populate a notification
event.waitUntil(
fetch(SOME_API_ENDPOINT).then(function(response) {
if (response.status !== 200) {
// Either show a message to the user explaining the error
// or enter a generic message and handle the
// onnotificationclick event to direct the user to a web page
console.log('Looks like there was a problem. Status Code: ' + response.status);
throw new Error();
}
// Examine the text in the response
return response.json().then(function(data) {
if (data.error || !data.notification) {
console.error('The API returned an error.', data.error);
throw new Error();
}
var title = data.notification.title;
var message = data.notification.message;
var icon = data.notification.icon;
var notificationTag = data.notification.tag;
return self.registration.showNotification(title, {
body: message,
icon: icon,
tag: notificationTag
});
});
}).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';
var icon = URL_TO_DEFAULT_ICON;
var notificationTag = 'notification-error';
return self.registration.showNotification(title, {
body: message,
icon: icon,
tag: notificationTag
});
})
);
});
同样值得强调的是,event.waitUntil()
接受一个 promise,这会导致 showNotification()
返回的 promise,这意味着在异步 fetch()
调用完成且显示通知之前,我们的事件监听器不会退出。
您会发现,即使出现错误,我们也会显示通知。这是因为,如果我们不这样做,Chrome 就会显示自己的一般通知。
在用户点击通知时打开网址
当用户点击通知时,系统会在您的 Service Worker 中分派 notificationclick
事件。在处理程序中,您可以执行适当的操作,例如聚焦标签页或打开具有特定网址的窗口:
self.addEventListener('notificationclick', function(event) {
console.log('On notification click: ', event.notification.tag);
// Android doesn't close the notification when you click on it
// See: http://crbug.com/463146
event.notification.close();
// This looks to see if the current is already open and
// focuses if it is
event.waitUntil(
clients.matchAll({
type: "window"
})
.then(function(clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
if (client.url == '/' && 'focus' in client)
return client.focus();
}
if (clients.openWindow) {
return clients.openWindow('/');
}
})
);
});
此示例通过聚焦现有的同源标签页(如果存在)并打开一个新标签页,打开浏览器并进入网站来源的根目录。
我们专门发布了一篇博文,介绍您可以使用 Notification API 执行的一些操作。
取消订阅用户的设备
您已订阅用户的设备,用户也收到了推送消息,但如何退订用户?
退订用户设备所需的主要操作是对 PushSubscription 对象调用 unsubscribe()
方法,并从服务器中移除端点(这样您就不会发送您知道不会接收的推送消息)。以下代码就是执行此操作:
function unsubscribe() {
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = true;
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
// To unsubscribe from push messaging, you need get the
// subscription object, which you can call unsubscribe() on.
serviceWorkerRegistration.pushManager.getSubscription().then(
function(pushSubscription) {
// Check we have a subscription to unsubscribe
if (!pushSubscription) {
// No subscription object, so set the state
// to allow the user to subscribe to push
isPushEnabled = false;
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
return;
}
var subscriptionId = pushSubscription.subscriptionId;
// TODO: Make a request to your server to remove
// the subscriptionId from your data store so you
// don't attempt to send them push messages anymore
// We have a subscription, so call unsubscribe on it
pushSubscription.unsubscribe().then(function(successful) {
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
isPushEnabled = false;
}).catch(function(e) {
// We failed to unsubscribe, this can lead to
// an unusual state, so may be best to remove
// the users data from your data store and
// inform the user that you have done so
console.log('Unsubscription error: ', e);
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
});
}).catch(function(e) {
console.error('Error thrown while unsubscribing from push messaging.', e);
});
});
}
保持订阅处于最新状态
订阅可能会在 FCM 和您的服务器之间不同步。确保您的服务器会解析 FCM API 发送 POST 的响应正文,以查找 error:NotRegistered
和 canonical_id
结果,如 FCM 文档中所述。
订阅还可能在 Service Worker 和您的服务器之间不同步。例如,在成功订阅/退订后,不稳定的网络连接可能会导致您无法更新服务器;或者用户可能会撤消通知权限,从而触发自动退订。如需处理此类情况,请定期检查 serviceWorkerRegistration.pushManager.getSubscription()
的结果(例如在网页加载时),并将其与服务器同步。如果您不再拥有订阅且 Notification.permission == 'granted',也可能需要自动重新订阅。
在 sendSubscriptionToServer()
中,您需要考虑在更新 endpoint
时如何处理失败的网络请求。一种解决方案是跟踪 Cookie 中 endpoint
的状态,以确定您的服务器是否需要最新详细信息。
完成上述所有步骤后,您便可以在 Chrome 46 中全面实现 Web 上的推送消息传递。但仍有一些规范化功能可以简化操作(例如用于触发推送消息的标准 API),但此版本可让您立即开始将推送消息构建到您的 Web 应用中。
如何调试您的 Web 应用
实现推送消息时,错误将出现在以下两个位置之一:页面或 Service Worker。
可使用 DevTools 调试网页中的错误。您可以通过以下两种方式调试 Service Worker 问题:
- 依次转到 chrome://inspect > Service Worker。除了当前正在运行的 Service Worker,此视图不提供太多信息。
- 转到 chrome://serviceworker-internals,您可以在其中查看 Service Worker 的状态,以及查看错误(如有)。在开发者工具提供类似的功能集之前,此页面只是临时页面。
对于刚接触 Service Worker 的人,我可以给出的一个最佳提示是,利用名为“Open DevTools window and pause JavaScript execution on Service Worker to debugging”(打开开发者工具窗口并暂停在 Service Worker 启动时暂停 JavaScript 执行)的复选框。此复选框将在 Service Worker 的开头添加一个断点并暂停执行,这使您能够恢复或单步调试 Service Worker 脚本,并查看是否遇到任何问题。
![显示“暂停执行”复选框在 serviceworker-internals 上的位置的屏幕截图。](https://developer.chrome.google.cn/static/blog/push-notifications-on-the-open-web/image/screenshot-showing-where-c2ca72dd7d118.png?authuser=7&hl=zh-cn)
如果 FCM 和 Service Worker 的推送事件之间似乎有问题,那么您就没法进行太多调试来调试问题,因为您无法看到 Chrome 是否收到了任何内容。需要确保的关键在于,当您的服务器发出 API 调用时,FCM 的响应会成功。结果应如下所示:
{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}
请注意 "success": 1
响应。如果您看到失败,则表示 FCM 注册 ID 有误,推送消息未发送到 Chrome。
调试 Chrome(Android 版)上的 Service Worker
目前,在 Chrome(Android 版)上调试 Service Worker 还不明显。您需要前往 chrome://inspect,找到您的设备并查找名为“Worker pid:....”的列表项,其中包含您的 Service Worker 的网址。
![显示 Service Worker 在 Chrome 检查中的位置的屏幕截图](https://developer.chrome.google.cn/static/blog/push-notifications-on-the-open-web/image/screenshot-showing-where-03978e62edfe4.png?authuser=7&hl=zh-cn)
推送通知的用户体验
Chrome 团队正在汇总一个有关推送通知用户体验的最佳实践文档,以及一个介绍使用推送通知时的一些极端情况的文档。
Chrome 和开放网络推送消息功能的未来
本部分详细介绍了您应了解的一些 Chrome 特定部分,以及该实现与其他浏览器实现的区别。
网络推送协议和端点
Push API 标准的优点在于,您应该能够通过实现网络推送协议获取端点,将其传递给服务器并发送推送消息。
网络推送协议是一种推送提供程序可以实现的新标准,让开发者不必操心推送提供程序是谁。这样做的目的是,让开发者不必注册 API 密钥和发送特殊格式的数据,就像使用 FCM 时必须执行的操作。
Chrome 是第一个实现 Push API 的浏览器,但 FCM 不支持网络推送协议,这就是 Chrome 要求 gcm_sender_id
的原因,并且您需要为 FCM 使用 RESTful API。
Chrome 的最终目标是朝着将 Web 推送协议与 Chrome 和 FCM 结合使用。
在此之前,您需要检测端点“https://fcm.googleapis.com/fcm/send”,并将其与其他端点分开处理,即以特定方式设置载荷数据的格式并添加授权密钥。
如何实现网络推送协议?
Firefox Nightly 目前正在开发推送功能,很可能是第一个实现网络推送协议的浏览器。
常见问题解答
规格在哪里?
https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/
如果我的网络身份有多个源,或者我既有网络又有原生,我可以防止出现重复的通知吗?
此问题还没有解决方案,但您可以按照 Chromium 的进度跟踪。
理想的场景是为用户设备设定某种 ID,然后在服务器端匹配原生应用和 Web 应用的订阅 ID,并决定向哪个 ID 发送推送消息。您可以通过屏幕尺寸、设备型号以及在 Web 应用和原生应用之间共享生成的密钥来实现此目的,但每种方法各有利弊。
为什么我需要 gcm_sender_id?
只有这样,Chrome、Opera for Android 和 Samsung 浏览器才能使用 Firebase Cloud Messaging (FCM) API。目标是在标准最终确定且 FCM 可支持后使用网络推送协议。
为什么不使用 Web Sockets 或服务器发送事件 (EventSource)?
使用推送消息的优势在于,即使页面关闭,您的 Service Worker 也会被唤醒并能够显示通知。Web Sockets 和 EventSource 的连接会在页面或浏览器关闭时关闭。
如果我不需要传送后台事件,该怎么办?
如果您不需要后台传送,Web Sockets 是一个很好的选择。
何时可以在不显示通知的情况下使用推送(即无声背景推送)?
虽然目前还没有推出此功能的时间表,但有一个实现后台同步的意图,虽然未做出决定或规范,但关于如何启用后台同步静默推送,仍存在一些讨论。
为什么这需要 HTTPS?如何在开发期间解决此问题?
Service Worker 需要安全源,以确保 Service Worker 脚本来自预期源,并且不会受到中间人攻击。目前,这意味着在实际网站上使用 HTTPS,尽管 localhost 在开发过程中可以正常使用。
浏览器支持情况如何?
Chrome 已支持稳定版,Mozilla 也已在 Firefox Nightly 中推送消息。 如需了解详情,请参阅实现 Push API bug;您可以在此处跟踪其通知实现情况。
我可以在一段时间后移除通知吗?
目前还不能,但我们计划添加相关支持,以获取当前显示的通知列表。如果您有一个用例,需要在通知显示后为其设置到期时间,我们很想知道这是什么,因此请添加评论,我们会将其转达给 Chrome 团队。
如果您只需要在一段时间后停止向用户发送推送通知,而不在意通知保持可见的时间,则可以使用 FCM 的存留时间 (ttl) 参数,点击此处了解详情。
在 Chrome 中推送消息有哪些限制?
该博文会介绍一些限制:
- Chrome 将 CCM 用作推送服务会产生许多专有要求。我们正在共同努力,看看未来是否可以提升其中的一些机制。
- 您必须在收到推送消息时显示通知。
- Chrome 桌面版会提醒用户,如果 Chrome 未运行,则无法收到推送消息。这与 ChromeOS 和 Android 不同,在 ChromeOS 和 Android 中,系统会始终接收推送消息。
我们不应该使用 Permissions API 吗?
Permission API 是在 Chrome 中实现的,但不一定在所有浏览器中都可用。您可以点击此处了解详情。
当我点击通知时,为什么 Chrome 无法打开上一个标签页?
此问题只会影响当前不受 Service Worker 控制的页面。您可以点击此处了解详情。
如果在用户设备收到推送时通知已过期,该怎么办?
收到推送消息时,您必须显示通知。 如果您想要发送通知但该通知仅在特定时间段内有用,您可以在 CCM 上使用“time_to_live”参数,这样 FCM 在过期时间过后便不会发送推送消息。
如果我发送了 10 条推送消息,但只希望设备接收一条,会发生什么情况?
FCM 有一个“collapse_key”参数,您可以使用该参数指示 FCM 将任何具有相同“collapse_key”的待处理消息替换为新消息。