首页 > 解决方案 > PWA 停止在 android 应用关闭时接收推送通知

问题描述

我创建了一个带有 Service Worker 的简单 PWA 应用程序,它在需要时从我的服务器接收推送通知,并向用户显示通知。当应用程序在前台运行并且应用程序在后台运行几分钟时,这非常有用,推送通知会被接收并按预期显示给用户。但是在后台过了几分钟或者如果应用程序关闭,PWA 将停止接收这些推送通知。

到目前为止我所拥有的:

服务工作者.js

self.addEventListener('push', (e) => {
  let notificationData
  e.waitUntil(
    clients.matchAll({ type: 'window' }).then(function(clientList) {
      const client = clientList && clientList[0]
      if (e.data && client && client.visibilityState !== 'visible') {
        const envelope = e.data.json()
        // Process the notification
        // ...
        e.waitUntil(self.registration.showNotification(data.subject, options))
      }
    })
  )
})

index.js

  async registerPushNotificationToWorker() {
    if ('serviceWorker' in navigator) {
      try {
        const swRegistration = await navigator.serviceWorker.getRegistration()
        let subscription = await swRegistration.pushManager.getSubscription()
        let subscriptionJson
        if (subscription === null) {
          subscriptionJson = await subscribeUser()
        } else {
          subscriptionJson = subscription.toJSON()
        }
        // Save subscriptionJson on server
        // ...
      } catch (e) {
        console.log('Service Worker registration failed: ', e)
      }
    }
  }

  async subscribeUser() {
    if ('serviceWorker' in navigator) {
      const swRegistration = await navigator.serviceWorker.ready
      try {
        const pushSubscription = await swRegistration.pushManager.subscribe({
          userVisibleOnly: true,
          applicationServerKey
        })
        return pushSubscription.toJSON()
      } catch (e) {
        console.log('Error', e)
        if (Notification.permission === 'denied') {
          console.warn('Permission for notifications was denied')
        } else {
          console.error('Unable to subscribe to push', e)
        }
      }
    }
    return null
  }

据我了解,即使应用程序已关闭,也应在收到推送通知时唤醒 android 上的服务人员。我应该为服务工作者做一个特定的代码,以便在需要时被唤醒?

标签: androidpush-notificationprogressive-web-apps

解决方案


发现了问题。这里的问题是服务工作者上的事件侦听器让客户端验证应用程序是否已经打开,但我假设列表中总会有一个客户端,即使应用程序关闭也是如此。正确的方法是这样的:

self.addEventListener('push', (e) => {
  let notificationData
  e.waitUntil(
    clients.matchAll({ type: 'window' }).then(function(clientList) {
      const client = clientList.find(c => c.visibilityState === 'visible') // <- This validation
      if (e.data && !client) {
        const envelope = e.data.json()
        // Process the notification
        // ...
        e.waitUntil(self.registration.showNotification(data.subject, options))
      }
    })
  )
})

推荐阅读