You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constwebpush=require('web-push');// VAPID keys should only be generated only once.constvapidKeys=webpush.generateVAPIDKeys();webpush.setGCMAPIKey('<Your GCM API Key Here>');webpush.setVapidDetails('mailto:[email protected]',vapidKeys.publicKey,vapidKeys.privateKey);// pushSubscription是前端通过swReg.pushManager.subscribe获取到的subscriptionconstpushSubscription={endpoint: '.....',keys: {auth: '.....',p256dh: '.....'}};webpush.sendNotification(pushSubscription,'Your Push Payload Text');
Service Worker中的self.clients对象提供了Client的访问,Client接口表示一个可执行的上下文,如Worker或SharedWorker。Window客户端由更具体的WindowClient表示。 你可以从Clients.matchAll()和Clients.get()等方法获取Client/WindowClient对象。
在上一篇文章Service Worker学习与实践(二)——PWA简介中,已经讲到
PWA
的起源,优势与劣势,并通过一个简单的例子说明了如何在桌面端和移动端将一个PWA
安装到桌面上,这篇文章,将通过一个例子阐述如何使用Service Worker
的消息推送功能,并配合PWA
技术,带来原生应用般的消息推送体验。Notification
说到底,
PWA
的消息推送也是服务端推送的一种,常见的服务端推送方法,例如广泛使用的轮询、长轮询、Web Socket
等,说到底,都是客户端与服务端之间的通信,在Service Worker
中,客户端接收到通知,是基于Notification来进行推送的。那么,我们来看一下,如何直接使用
Notification
来发送一条推送呢?下面是一段示例代码:在控制台敲下上述代码后,则会弹出以下通知:
然而,
Notification
这个API
,只推荐在Service Worker
中使用,不推荐在主线程中使用,在Service Worker
中的使用方法为:读者可以在MDN Web Docs关于
Notification
在Service Worker
中的相关用法,在本文就不浪费大量篇幅来进行较为详细的阐述了。申请推送的权限
如果浏览器直接给所有开发者开放向用户推送通知的权限,那么势必用户会受到大量垃圾信息的骚扰,因此这一权限是需要申请的,如果用户禁止了消息推送,开发者是没有权利向用户发起消息推送的。我们可以通过serviceWorkerRegistration.pushManager.getSubscription方法查看用户是否已经允许推送通知的权限。修改
sw-register.js
中的代码:上面的代码调用了
swReg.pushManager
的getSubscription
,可以知道用户是否已经允许进行消息推送,如果swReg.pushManager.getSubscription
的Promise
被reject
了,则表示用户还没有订阅我们的消息,调用subscribeUser
方法,向用户申请消息推送的权限:上面的代码通过serviceWorkerRegistration.pushManager.subscribe向用户发起订阅的权限,这个方法返回一个
Promise
,如果Promise
被resolve
,则表示用户允许应用程序推送消息,反之,如果被reject
,则表示用户拒绝了应用程序的消息推送。如下图所示:serviceWorkerRegistration.pushManager.subscribe
方法通常需要传递两个参数:userVisibleOnly
,这个参数通常被设置为true
,用来表示后续信息是否展示给用户。applicationServerKey
,这个参数是一个Uint8Array
,用于加密服务端的推送信息,防止中间人攻击,会话被攻击者篡改。这一参数是由服务端生成的公钥,通过urlB64ToUint8Array
转换的,这一函数通常是固定的,如下所示:关于服务端公钥如何获取,在文章后续会有相关阐述。
处理拒绝的权限
如果在调用
serviceWorkerRegistration.pushManager.subscribe
后,用户拒绝了推送权限,同样也可以在应用程序中,通过Notification.permission获取到这一状态,Notification.permission
有以下三个取值,:granted
:用户已经明确的授予了显示通知的权限。denied
:用户已经明确的拒绝了显示通知的权限。default
:用户还未被询问是否授权,在应用程序中,这种情况下权限将视为denied
。密钥生成
上述代码中的
applicationServerPublicKey
通常情况下是由服务端生成的公钥,在页面初始化的时候就会返回给客户端,服务端会保存每个用户对应的公钥与私钥,以便进行消息推送。在我的示例演示中,我们可以使用
Google
配套的实验网站web-push-codelab生成公钥与私钥,以便发送消息通知:发送推送
在
Service Worker
中,通过监听push
事件来处理消息推送:在上面的代码中,在
push
事件回调中,通过event.data.text()
拿到消息推送的文本,然后调用上面所说的self.registration.showNotification
来展示消息推送。服务端发送
那么,如何在服务端识别指定的用户,向其发送对应的消息推送呢?
在调用
swReg.pushManager.subscribe
方法后,如果用户是允许消息推送的,那么该函数返回的Promise
将会resolve
,在then
中获取到对应的subscription
。subscription
一般是下面的格式:使用
Google
配套的实验网站web-push-codelab,发送消息推送。web-push
在服务端,使用web-push-libs,实现公钥与私钥的生成,消息推送功能,Node.js版本。
上面的代码中,
GCM API Key
需要在Firebase console中申请,申请教程可参考这篇博文。在这个我写的示例
Demo
中,我把subscription
写死了:交互响应
默认情况下,推送的消息点击后是没有对应的交互的,配合clients API可以实现一些类似于原生应用的交互,这里参考了这篇博文的实现:
新窗口打开
使用
clients.openWindow
在新窗口打开一个网页:聚焦已经打开的页面
利用
cilents
提供的相关API
获取,当前浏览器已经打开的页面URLs
。不过这些URLs
只能是和你SW
同域的。然后,通过匹配URL
,通过matchingClient.focus()
进行聚焦。没有的话,则新打开页面即可。检测是否需要推送
如果用户已经停留在当前的网页,那我们可能就不需要推送了,那么针对于这种情况,我们应该怎么检测用户是否正在网页上呢?
合并消息
该场景的主要针对消息的合并。比如,当只有一条消息时,可以直接推送,那如果该用户又发送一个消息呢? 这时候,比较好的用户体验是直接将推送合并为一个,然后替换即可。 那么,此时我们就需要获得当前已经展示的推送消息,这里主要通过
registration.getNotifications() API
来进行获取。该API
返回的也是一个Promise
对象。通过Promise
在resolve
后拿到的notifications
,判断其length
,进行消息合并。小结
本文通过一个简单的例子,讲述了
Service Worker
中消息推送的原理。Service Worker
中的消息推送是基于Notification API
的,这一API
的使用首先需要用户授权,通过在Service Worker
注册时的serviceWorkerRegistration.pushManager.subscribe
方法来向用户申请权限,如果用户拒绝了消息推送,应用程序也需要相关处理。消息推送是基于谷歌云服务的,因此,在国内,收到
GFW
的限制,这一功能的支持并不好,Google
提供了一系列推送相关的库,例如Node.js
中,使用web-push来实现。一般原理是:在服务端生成公钥和私钥,并针对用户将其公钥和私钥存储到服务端,客户端只存储公钥。Service Worker
的swReg.pushManager.subscribe
可以获取到subscription
,并发送给服务端,服务端利用subscription
向指定的用户发起消息推送。消息推送功能可以配合
clients API
做特殊处理。如果用户安装了
PWA
应用,即使用户关闭了应用程序,Service Worker
也在运行,即使用户未打开应用程序,也会收到消息通知。在下一篇文章中,我将尝试在我所在的项目中使用
Service Worker
,并通过Webpack
和Workbox
配置来讲述Service Worker
的最佳实践。The text was updated successfully, but these errors were encountered: