我正在使用 Firebase Cloud Messaging + Service Worker 来处理后台推送通知。

单击通知(包含一些数据 + 一个 URL)时,我想:

  • 如果窗口已经在所需的 URL 上,则聚焦窗口
  • 如果已经有事件选项卡打开,则导航到 URL 并聚焦它
  • 如果以上条件都不满足,则打开 URL 的新窗口

  • 第 1 点和第 3 点适用于以下 SW 代码。

    出于某种原因,第 2 点不起作用。 client.navigate() promise 被拒绝:
    Uncaught (in promise) TypeError: Cannot navigate to URL: http://localhost:4200/tasks/-KMcCHZdQ2YKCgTA4ddd
    我认为这可能是由于缺少 https,但从我的阅读来看,似乎 localhost 在使用 SW 开发时被列入白名单。

    firebase-messaging-sw.js:
    // Give the service worker access to Firebase Messaging.
    // Note that you can only use Firebase Messaging here, other Firebase libraries
    // are not available in the service worker.
    importScripts('https://www.gstatic.com/firebasejs/3.5.3/firebase-app.js');
    importScripts('https://www.gstatic.com/firebasejs/3.5.3/firebase-messaging.js');
    
    // Initialize the Firebase app in the service worker by passing in the
    // messagingSenderId.
    firebase.initializeApp({
      'messagingSenderId': 'XXXX'
    });
    
    const messaging = firebase.messaging();
    
    messaging.setBackgroundMessageHandler(payload => {
      console.log('[firebase-messaging-sw.js] Received background message ', payload);
      let notificationData = JSON.parse(payload.data.notification);
      const notificationOptions = {
        body: notificationData.body,
        data: {
          clickUrl: notificationData.clickUrl
        }
      };
    
      return self.registration.showNotification(notificationData.title,
        notificationOptions);
    });
    
    self.addEventListener('notificationclick', event => {
      console.log('[firebase-messaging-sw.js] Notification OnClick: ', event);
    
      // Android doesn’t close the notification when you click on it
      // See: http://crbug.com/463146
      event.notification.close();
    
      // This looks to see if the current is already open and
      // focuses if it is
      event.notification.close();
      let validUrls = /localhost:4200/;
      let newUrl = event.notification.data.clickUrl || '';
    
      function endsWith(str, suffix) {
        return str.indexOf(suffix, str.length - suffix.length) !== -1;
      }
    
      event.waitUntil(
        clients.matchAll({
          includeUncontrolled: true,
          type: 'window'
        })
        .then(windowClients => {
          for (let i = 0; i < windowClients.length; i++) {
            let client = windowClients[i];
            if (validUrls.test(client.url) && 'focus' in client) {
              if (endsWith(client.url, newUrl)) {
                console.log('URL already open, focusing.');
                return client.focus();
              } else {
                console.log('Navigate to URL and focus', client.url, newUrl);
                return client.navigate(newUrl).then(client => client.focus());
              }
            }
          }
    
          if (clients.openWindow) {
            console.log('Opening new window', newUrl);
            return clients.openWindow(newUrl);
          }
        })
      );
    
    });
    

    我的绝大多数软件代码取自:
    https://gist.github.com/vibgy/0c5f51a8c5756a5c408da214da5aa7b0

    最佳答案

    我建议您从 includeUncontrolled: true 中删除 clients.matchAll()

    您正在处理的 WindowClient 可能没有将当前服务工作人员作为其事件服务工作人员。根据 the specification for WindowClient.navigate() 中的第 4 项:



    如果您在确定客户端当前由 Service Worker 控制时可以重现该问题,那么可能还有其他事情发生,但这就是我要尝试的第一步。

    关于push-notification - ServiceWorker WindowClient.navigate promise 被拒绝,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40597867/

    10-10 20:24