解析)
Angular Service Worker 推送通知实战SwPush 订阅、通知负载与点击操作onActionClick解析【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular本文围绕 Angular 官方文档中 Service Worker 推送通知指南展开讲解如何在 Angular 应用中通过SwPush服务接收推送、构造合规的通知负载payload以及如何利用onActionClick与四种内置操作Operations精确控制通知点击后的行为。读完本文你将掌握从订阅推送、本地调试到点击路由处理的完整链路并能对照 Angular 仓库源码理解 Service Worker 侧的真实事件处理逻辑与 URL 解析规则。推送通知在 Angular 中的角色推送通知Push notifications是一种强用户触达手段借助 Service Worker通知可以在你的应用没有处于焦点状态甚至已关闭页面时依然送达设备。Angular 内置的 Service Worker即angular/service-worker由构建工具生成的ngsw-worker.js在原生 Push API / Notifications API 之上封装了一层应用级能力——它负责展示推送通知并统一处理通知点击事件应用侧则通过SwPush服务订阅这些交互结果。从源码结构看整条链路分为两侧应用侧主线程SwPush服务定义在 push.ts它通过NgswCommChannellow_level.ts与 Worker 通信把 Worker 广播的消息流映射为若干ObservableWorker 侧事件处理核心是 driver.ts 中的Driver类入口在 main.ts 中实例化。Driver监听push、notificationclick、notificationclose等事件决定是弹出系统通知、打开/聚焦客户端窗口还是向所有已注册客户端广播消息。通知负载Notification payload要触发一次推送通知你需要向用户的设备推送一条携带合法 payload 的消息。Angular 对负载的约定是顶层对象包含一个notification键其值即为浏览器NotificationOptions的合法字段。官方文档中给出的完整字段集如下见 SwPush 的 API 注释{ notification: { actions: NotificationAction[], badge: USVString, body: DOMString, data: any, dir: auto|ltr|rtl, icon: USVString, image: USVString, lang: DOMString, renotify: boolean, requireInteraction: boolean, silent: boolean, tag: DOMString, timestamp: DOMTimeStamp, title: DOMString, vibrate: number[] } }其中只有title是必需的其余字段可选。这一点在 Worker 源码中得到直接印证Driver的handlePush方法中若负载缺少notification或notification.title则只广播消息、不弹出通知driver.tsprivate async handlePush(data: any): Promisevoid { await this.broadcast({ type: PUSH, data, }); if (!data.notification || !data.notification.title) { return; } const desc data.notification as {[key: string]: string | undefined}; let options: {[key: string]: string | undefined} {}; NOTIFICATION_OPTION_NAMES.filter((name) Object.hasOwn(desc, name)).forEach( (name) (options[name] desc[name]), ); await this.scope.registration.showNotification(desc[title]!, options); }这里有两个值得注意的实现细节先广播、后弹通知。无论负载是否包含可展示的通知Worker 都会先向所有客户端广播一条PUSH类型消息——这就是应用侧SwPush.messages可感知任意推送数据包括纯业务数据的原因。白名单过滤通知选项。Worker 仅透传NOTIFICATION_OPTION_NAMES中列出的字段driver.tsactions、badge、body、data、dir、icon、image、lang、renotify、requireInteraction、silent、tag、timestamp、title、vibrate再调用registration.showNotification(title, options)展示通知。负载中data字段会原样挂到通知上后续点击处理时再从notification.data中读取。无后端场景下的 Chrome 本地调试官方指南给出了一个非常实用的免后端调试技巧在 Chrome 中打开DevTools → Application → Service Workers直接使用面板提供的Push输入框粘贴一个 JSON 通知负载即可模拟一次推送事件验证 Worker 是否正确弹出了通知。订阅与退订SwPush 的应用侧用法应用侧所有推送交互都收敛到SwPush这一个服务上push.ts。典型用法是把它注入组件或服务中订阅调用requestSubscription({serverPublicKey})该方法会先请求用户授权返回一个解析为PushSubscription的Promise。退订调用unsubscribe()。状态检查通过SwPush.isEnabled确认 Service Worker 是否受浏览器支持且已通过ServiceWorkerModule启用。从 requestSubscription 的实现 可以看到关键行为requestSubscription(options: {serverPublicKey: string}): PromisePushSubscription { if (!this.sw.isEnabled || this.pushManager null) { return Promise.reject(new Error(ERR_SW_NOT_SUPPORTED)); } const pushOptions: PushSubscriptionOptionsInit {userVisibleOnly: true}; let key this.decodeBase64(options.serverPublicKey.replace(/_/g, /).replace(/-/g, )); // ...将密钥字符串转为 Uint8Array 后赋值给 applicationServerKey pushOptions.applicationServerKey applicationServerKey; // ...pushManager.subscribe(pushOptions) }serverPublicKey需要是 URL-safe Base64 编码的应用服务器公钥源码中会先把_换回/、-换回再解码订阅固定设置userVisibleOnly: true用户拒绝授权、浏览器不支持 Push API 或 Service Worker 时Promise会被拒绝unsubscribe()在没有活跃订阅时会抛出NOT_SUBSCRIBED_TO_PUSH_NOTIFICATIONS运行时错误push.ts。通知点击处理Notification click handlingnotificationclick事件的默认行为是关闭该通知并向SwPush.notificationClicks发射一条消息。这个行为由 Worker 侧的handleClick实现driver.ts——方法开头即notification.close()末尾再广播NOTIFICATION_CLICK消息。如果希望在点击时执行额外的浏览器端操作尤其是当前没有任何打开的客户端窗口时可以在负载的data对象中添加onActionClick属性并为default键提供一个操作条目{ notification: { title: New Notification!, data: { onActionClick: { default: {operation: openWindow, url: foo} } } } }Worker 处理点击时的核心逻辑是先把点击动作名归一化——若action为空字符串或undefined则取default条目否则按具体动作名查找然后解析目标 URLconst notificationAction action || action undefined ? default : action; const onActionClick notification?.data?.onActionClick?.[notificationAction]; const urlToOpen new URL(onActionClick?.url ?? , this.scope.registration.scope).href;内置操作OperationsAngular Service Worker 支持以下四种操作完整表格继承自官方文档操作说明openWindow在指定 URL 处打开一个新标签页。focusLastFocusedOrOpen聚焦最近一次聚焦的客户端如果没有打开的客户端则在指定 URL 打开新标签页。navigateLastFocusedOrOpen聚焦最近一次聚焦的客户端并将其导航到指定 URL如果没有打开的客户端则在指定 URL 打开新标签页。sendRequest向指定 URL 发起一个简单的 GET 请求。重要原文档 IMPORTANT 提示URL 是相对于 Service Worker 注册作用域registration scope解析的。如果某个onActionClick条目没有定义url则直接使用 Service Worker 的注册作用域本身。这条规则与源码严格对应new URL(onActionClick?.url ?? , this.scope.registration.scope)正是以注册作用域为基准做相对 URL 解析。各操作的底层实现同样可在 handleClick 中逐一对照openWindow→clients.openWindow(urlToOpen)focusLastFocusedOrOpen→ 先getLastFocusedMatchingClient(this.scope)找到最后一个聚焦客户端并focus()找不到才openWindow(urlToOpen)navigateLastFocusedOrOpen→ 找到客户端则client.navigate(urlToOpen)后focus()找不到则openWindow(urlToOpen)sendRequest→this.scope.fetch(urlToOpen)fetch不传 method 时默认即为 GET在 Worker 后台静默完成未识别的操作名走default分支不做任何窗口操作。无论执行哪种操作handleClick最后都会广播NOTIFICATION_CLICK消息携带action与被过滤后的通知选项由应用侧SwPush.notificationClicks接收。上述行为并非仅靠阅读源码推断仓库内的测试用例对每个操作都做了独立验证包括「指定url时打开scope url」「未指定url时回退到注册作用域根路径」「无最后聚焦客户端时回退为openWindow」等分支见 happy_spec.ts 中openWindow与focusLastFocusedOrOpen的 describe 块以及后续对navigateLastFocusedOrOpen、sendRequest和缺失onActionClick场景的断言。通知动作按钮ActionsActions 提供了一种方式让用户可以与通知进行更细粒度的交互通过actions属性定义一组可用动作每个动作在通知上呈现为一个可点击的按钮再配合data中的onActionClick把每个按钮绑定到具体的操作上{ notification: { title: New Notification!, actions: [ {action: foo, title: Open new tab}, {action: bar, title: Focus last}, {action: baz, title: Navigate last}, {action: qux, title: Send request in the background}, {action: other, title: Just notify existing clients} ], data: { onActionClick: { default: {operation: openWindow}, foo: {operation: openWindow, url: /absolute/path}, bar: {operation: focusLastFocusedOrOpen, url: relative/path}, baz: {operation: navigateLastFocusedOrOpen, url: https://other.domain.com/}, qux: {operation: sendRequest, url: https://yet.another.domain.com/} } } } }这个示例覆盖了四种操作加上一个“兜底”场景other按钮在onActionClick中没有对应条目。重要原文档 IMPORTANT 提示如果某个动作没有对应的onActionClick条目则通知会被关闭并且会向已存在的客户端通知SwPush.notificationClicks——也就是退回默认行为只做应用内消息分发不产生任何窗口操作。对照handleClick源码可以推断其兜底机制当onActionClick?.[action]为undefined时switch (onActionClick?.operation)不命中任何分支直接break随后依旧广播NOTIFICATION_CLICK。测试用例中也专门验证了 “No matching onActionClick field” 与 “no onActionClick default” 两类场景下的行为happy_spec.ts。应用侧可订阅的完整事件流SwPush不止暴露notificationClicks。从 构造函数的消息映射 可以看到它与 Worker 广播的消息类型一一对应SwPush成员对应 Worker 广播类型触发时机messagesPUSH每次收到推送负载先于通知展示notificationClicksNOTIFICATION_CLICK用户点击通知主体或某个动作按钮notificationClosesNOTIFICATION_CLOSE通知被关闭含程序性关闭pushSubscriptionChangesPUSH_SUBSCRIPTION_CHANGE浏览器自动轮换/失效订阅时subscriptionpushManager.getSubscription()当前活跃订阅或null两个值得注意的 API 契约来自 push.ts 的文档注释notificationClicks/notificationCloses的notification字段不是Notification对象而是NotificationOptions对象并额外包含title未使用动作按钮时action为空字符串pushSubscriptionChanges携带oldSubscription/newSubscription二者任一可为null用于应对浏览器因订阅过期或密钥轮换引发的自动变更——这是生产推送系统中维护“订阅 → 用户”映射时不可缺少的信号。当 Service Worker 不可用时上述所有 Observable 都被替换为NEVER不发射任何值保证应用代码可以无条件注入SwPush而不抛异常。小结与适用前提回到官方指南的要点Angular Service Worker 的推送通知能力可以概括为三层负载层以notification为顶层键的 JSON 负载title必填其余遵循NotificationOptions白名单点击层onActionClickdefault 各动作键声明式绑定四种操作URL 一律相对注册作用域解析缺失条目自动回退为“关闭通知 通知已有客户端”应用层SwPush的五个 Observable 把 Worker 侧事件转成响应式流应用负责路由跳转、状态恢复等最终 UI 决策。适用前提与限制功能依赖浏览器对 Push API、Notifications API 和 Service Worker 的支持可用SwPush.isEnabled检查生产环境推送需要自备推送后端与 VAPID 公钥requestSubscription的serverPublicKey本地开发则可完全依赖 Chrome DevTools 的 Service Workers 面板进行无后端验证。仓库中的示例组件 service_worker_component.ts 演示了SwPush注入、订阅与点击监听的完整组合可作为动手实践的起点。【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考