此 Codelab 将逐步向您展示如何构建推送通知客户端。 学完此 Codelab 后,您将拥有一个具备以下特征的客户端:
- 为用户订阅推送通知。
- 接收推送消息并将其显示为通知。
- 为用户退订推送通知。
本 Codelab 侧重于帮助您边做边学,不会过多讨论概念。阅读推送的工作原理,了解推送通知概念。
此 Codelab 的服务器代码已完成。在本 Codelab 中,您只需实现客户端。如需了解如何实现推送通知服务器,请参阅 Codelab:构建推送通知服务器。
浏览器兼容性
此 Codelab 已知可与以下操作系统和浏览器组合搭配使用:
- Windows:Chrome、Edge
- macOS:Chrome、Firefox
- Android:Chrome、Firefox
已知此 Codelab 无法在以下操作系统(或操作系统和浏览器组合)上运行:
- macOS:Brave、Edge、Safari
- iOS
设置
设置身份验证
您需要先为服务器和客户端设置身份验证密钥,然后才能使推送通知正常运行。如需了解原因,请参阅为 Web 推送协议请求签名。通常,您会将 Secret 存储在 .env 文件中,如下所示。
VAPID_PUBLIC_KEY="BKiwTvD9HA…"
VAPID_PRIVATE_KEY="4mXG9jBUaU…"
VAPID_SUBJECT="mailto:test@test.test"
- 打开
public/index.js。 - 将
VAPID_PUBLIC_KEY_VALUE_HERE替换为您的公钥值。
注册 Service Worker
您的客户端需要 Service Worker 才能接收和显示通知。最好尽早注册 Service Worker。 如需了解更多背景信息,请参阅以通知形式接收和显示推送的消息。
将
// TODO add startup logic here注释替换为以下代码:if ('serviceWorker' in navigator && 'PushManager' in window) { navigator.serviceWorker.register('./service-worker.js').then(serviceWorkerRegistration => { console.info('Service worker was registered.'); console.info({serviceWorkerRegistration}); }).catch(error => { console.error('An error occurred while registering the service worker.'); console.error(error); }); subscribeButton.disabled = false; } else { console.error('Browser does not support service workers or push messages.'); } subscribeButton.addEventListener('click', subscribeButtonHandler); unsubscribeButton.addEventListener('click', unsubscribeButtonHandler);在 Chrome 中,打开开发者工具控制台。
您应该会看到控制台中记录了
Service worker was registered.消息。
请求推送通知权限
切勿在网页加载时请求发送推送通知的权限。 相反,您的界面应询问用户是否希望接收推送通知。 在他们明确确认(例如,通过点击按钮)后,您就可以开始正式流程,从浏览器获取推送通知权限。
在
public/index.js中,将subscribeButtonHandler()中的// TODO注释替换为以下代码:// Prevent the user from clicking the subscribe button multiple times. subscribeButton.disabled = true; const result = await Notification.requestPermission(); if (result === 'denied') { console.error('The user explicitly denied the permission request.'); return; } if (result === 'granted') { console.info('The user accepted the permission request.'); }返回应用标签页,然后点击订阅推送。您的浏览器或操作系统会询问您是否允许该网站向您发送推送通知。
选择允许(或浏览器/操作系统使用的等效短语)。在控制台中,您应该会看到一条消息,指明请求是被接受还是被拒绝。
订阅推送通知
订阅流程涉及与由浏览器供应商控制的 Web 服务(称为推送服务)进行交互。获取推送通知订阅信息后,您需要将其发送到服务器,并让服务器将其长期存储在数据库中。
将以下突出显示的代码添加到
subscribeButtonHandler():subscribeButton.disabled = true; const result = await Notification.requestPermission(); if (result === 'denied') { console.error('The user explicitly denied the permission request.'); return; } if (result === 'granted') { console.info('The user accepted the permission request.'); } const registration = await navigator.serviceWorker.getRegistration(); const subscribed = await registration.pushManager.getSubscription(); if (subscribed) { console.info('User is already subscribed.'); notifyMeButton.disabled = false; unsubscribeButton.disabled = false; return; } const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlB64ToUint8Array(VAPID_PUBLIC_KEY) }); notifyMeButton.disabled = false; fetch('/add-subscription', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(subscription) });
userVisibleOnly 选项必须为 true。未来或许可以推送消息而不显示用户可见的通知(静默推送),但出于隐私方面的考虑,浏览器目前不允许使用该功能。
applicationServerKey 值依赖于一个实用函数,该函数可将 base64 字符串转换为 Uint8Array。此值用于在您的服务器和推送服务之间进行身份验证。
退订推送通知
在用户订阅推送通知后,您的界面需要提供一种退订方式,以防用户改变主意,不想再接收推送通知。
- 将
unsubscribeButtonHandler()中的// TODO注释替换为以下代码:
const registration = await navigator.serviceWorker.getRegistration();
const subscription = await registration.pushManager.getSubscription();
fetch('/remove-subscription', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({endpoint: subscription.endpoint})
});
const unsubscribed = await subscription.unsubscribe();
if (unsubscribed) {
console.info('Successfully unsubscribed from push notifications.');
unsubscribeButton.disabled = true;
subscribeButton.disabled = false;
notifyMeButton.disabled = true;
}
接收推送消息并将其显示为通知
如前所述,您需要一个 Service Worker 来处理从服务器推送到客户端的消息的接收和显示。如需了解详情,请参阅接收推送的消息并将其显示为通知。
打开
public/service-worker.js,并将 Service Worker 的push事件处理脚本中的// TODO注释替换为以下代码:let data = event.data.json(); const image = 'logo.png'; const options = { body: data.options.body, icon: image } self.registration.showNotification( data.title, options );返回到应用标签页。
点击通知我。您应该会收到一条推送通知。
在其他受支持的浏览器中打开应用标签页的网址。完成订阅工作流,然后点击通知所有人。您应该会在每个设备上收到相同的推送通知。
您可以通过多种方式自定义通知。如需了解详情,请参阅 ServiceWorkerRegistration.showNotification() 的参数。
在用户点击通知时打开网址
在实际应用中,您可能会使用通知来重新吸引用户,并提示他们访问您的网站。 为此,您需要对 Service Worker 进行更多配置。
将 Service Worker 的
notificationclick事件处理脚本中的// TODO注释替换为以下代码:event.notification.close(); event.waitUntil(self.clients.openWindow('https://web.dev'));返回应用标签页,再向自己发送一条通知,然后点击该通知。您的浏览器应该会打开一个新标签页并加载
https://web.dev。
后续步骤
- 查看
ServiceWorkerRegistration.showNotification(),了解自定义通知的所有不同方式。 - 如需更深入地了解推送通知的工作原理,请参阅推送通知概览。
- 请参阅 Codelab:构建推送通知服务器,了解如何构建用于管理订阅和发送 Web 推送协议请求的服务器。
- 试用通知生成器,测试自定义通知的所有方式。