此 Codelab 将逐步向您展示如何构建推送通知客户端。完成本 Codelab 后,您将获得一个具备以下特征的客户端:
- 让用户订阅推送通知。
- 接收推送消息并将其显示为通知。
- 让用户退订推送通知。
此 Codelab 侧重于帮助您通过实践来学习,不会过多地介绍概念。请阅读推送的工作原理,了解推送通知的概念。
此 Codelab 的服务器代码已完成。在本 Codelab 中,您将仅实现客户端。如需了解如何实现推送通知服务器,请参阅 Codelab:构建推送通知服务器。
浏览器兼容性
此 Codelab 已知可在以下操作系统和浏览器组合上运行:
- Windows:Chrome、Edge
- macOS:Chrome、Firefox
- Android:Chrome、Firefox
此 Codelab 已知无法在以下操作系统(或操作系统和浏览器组合)上运行:
- macOS:Brave、Edge、Safari
- iOS
设置
点击 Remix to Edit 使项目可供修改。
设置身份验证
您需要先为服务器和客户端设置身份验证密钥,然后才能使推送通知正常运作。 如需了解原因,请参阅为网页推送协议请求签名。通常,您会将 Secret 存储在 .env 文件中,如下所示。
VAPID_PUBLIC_KEY="BKiwTvD9HA…" VAPID_PRIVATE_KEY="4mXG9jBUaU…" VAPID_SUBJECT="mailto:[email protected]" - 打开
public/index.js。 - 将
VAPID_PUBLIC_KEY_VALUE_HERE替换为您的公钥值。
注册 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.'); }返回到应用标签页,然后点击 Subscribe to push。您的浏览器或操作系统会询问您是否要允许该网站向您发送推送通知。
选择允许(或浏览器或操作系统使用的等效短语)。您应该会在控制台中看到一条消息,指明请求是被接受还是被拒绝。
订阅推送通知
订阅流程涉及与由浏览器供应商控制的 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,然后将服务工作线程的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() 的参数。
在用户点击通知时打开网址
在实际应用中,您可能会使用通知来重新吸引用户并提示他们访问您的网站。为此,您需要对服务工作线程进行更多配置。
将服务工作线程的
notificationclick事件处理脚本中的// TODO注释替换为以下代码:event.notification.close(); event.waitUntil(self.clients.openWindow('https://web.dev'));返回应用标签页,向自己发送另一条通知,然后点击该通知。浏览器应会打开一个新标签页并加载
https://web.dev。
后续步骤
- 请参阅
ServiceWorkerRegistration.showNotification(),了解自定义通知的所有不同方法。 - 如需深入了解推送通知的工作原理,请参阅推送通知概览。
- 请参阅 Codelab:构建推送通知服务器,了解如何构建用于管理订阅和发送 Web 推送协议请求的服务器。
- 不妨试试通知生成器,测试各种自定义通知的方法。