【问题标题】:ServiceWorker claiming late in the lifecycle to use client.navigate in notificationclick event handlerServiceWorker 在生命周期后期声称在 notificationclick 事件处理程序中使用 client.navigate
【发布时间】:2018-08-17 15:15:34
【问题描述】:

我有一个 Firebase 服务人员,它在从 Firebase 云消息传递 (FCM) 推送消息时显示通知。

它还发布了一个帖子,以便我的 React 应用可以相应地更新。

/* eslint-env worker */
/* eslint no-restricted-globals: 1 */
/* global firebase */
/* global clients */

import config from './config'

importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js')

const { FIREBASE_MESSAGING_SENDER_ID } = config

firebase.initializeApp({ messagingSenderId: FIREBASE_MESSAGING_SENDER_ID })
const messaging = firebase.messaging()

messaging.setBackgroundMessageHandler(payload => {
  const title = payload.data.title
  const options = {
    body: payload.data.body,
    icon: payload.data.icon,
    data: payload.data,
  }

  clients.matchAll({ includeUncontrolled: true }).then(clientz => {
    clientz.forEach(client => {
      sendMessageToClient(client, 'NEW_USER_NOTIFICATON')
    })
  })
  return self.registration.showNotification(title, options)
})

const sendMessageToClient = (client, message) => {
  const messageChannel = new MessageChannel()
  client.postMessage(message, [messageChannel.port2])
}

这一切都很好,但我已经添加了它的上下文。

我想要做的是有一个点击功能,专注于正确的窗口/选项卡并导航到传递给它的链接。或者,如果选项卡未打开,请打开一个新窗口并转到链接。

这是我到目前为止的代码,添加到上述文件中。

self.addEventListener('notificationclick', event => {
  const clickedNotification = event.notification
  const link = clickedNotification.data.link
  clickedNotification.close()
  const promiseChain = self.clients.claim()
    .then(() => self.clients
      .matchAll({
        type: 'window',
      })
    )
    .then(windowClients => {
      let matchingClient = null
      windowClients.forEach(client => {
        if (client.url.includes(matching_url)) {
          matchingClient = client
        }
      })
      if (matchingClient) {
        return matchingClient.navigate(link)
          .then(() => matchingClient.focus())
      }
      return clients.openWindow(link)
    })

  event.waitUntil(promiseChain)
})

所以,我意识到 then 内的链接 navigatefocus 可能是不好的做法,但现在,我只是想让它工作。然后我会尝试想出一个聪明的解决方案。

所以我的代码的问题是clients.claim() 似乎不起作用。 matchAll 不返回任何内容到下一个then,参数是一个空数组。

我可以简单地将includeUncontrolled: true 选项添加到matchAll,但navigate 命令仅适用于受控客户端实例。

如果我尝试使用经常引用的Google example 进行声明和导航,它工作正常:

self.addEventListener('activate', event => {
  event.waitUntil(self.clients.claim().then(() => {
    // See https://developer.mozilla.org/en-US/docs/Web/API/Clients/matchAll
    return self.clients.matchAll({type: 'window'});
  }).then(clients => {
    return clients.map(client => {
      // Check to make sure WindowClient.navigate() is supported.
      if ('navigate' in client) {
        return client.navigate('activated.html');
      }
    });
  }));
});

所以我被困住了。 serviceworker 会立即被激活,所以我假设它在那之后的任何时候都会声明一个客户端。

我是否爱上了一个随机的 ServiceWorker Gotcha? 是否只能在处理激活事件时使用和导航到声明?

如果能提供任何帮助,我将不胜感激。

干杯

【问题讨论】:

    标签: javascript push-notification firebase-cloud-messaging service-worker


    【解决方案1】:

    我无法让它工作。

    但我认为值得记录我的解决方法。

    我无法让client.navigatenotificationclick 事件处理程序中工作。

    因此,我只是发送了一个postMessage,其中包含要在我的应用中提取的 URL 以触发那里的重定向,而没有任何客户端在任何地方声明。

    self.addEventListener('notificationclick', event => {
      const clickedNotification = event.notification
      const link = clickedNotification.data.link
      clickedNotification.close()
      const promiseChain = self.clients.matchAll({
          type: 'window',
          includeUncontrolled: true,
        })
        .then(windowClients => {
          let matchingClient = null
          windowClients.forEach(client => {
            if (client.url.includes(matching_url)) {
              matchingClient = client
            }
          })
          if (matchingClient) {
            sendMessageToClient(matchingClient, { type: 'USER_NOTIFICATION_CLICKED', link })
            return matchingClient.focus()
          }
          return clients.openWindow(link)
        })
    
      event.waitUntil(promiseChain)
    })
    
    const sendMessageToClient = (client, message) => {
      const messageChannel = new MessageChannel()
      client.postMessage(message, [messageChannel.port2])
    }
    

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 2020-07-09
      • 1970-01-01
      • 2022-06-30
      • 1970-01-01
      • 2015-06-19
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      相关资源
      最近更新 更多