ServiceWorker WindowClient.navigate承诺被拒绝

时间:2016-11-14 21:09:28

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

我正在使用Firebase Cloud Messaging + Service工作人员处理后台推送通知。

点击通知(包含一些数据+网址)时,我想要:

  • 如果窗口已经在所需的URL上,请将窗口聚焦
  • 如果已打开活动标签
  • ,请导航至该网址并对其进行关注
  • 如果上述条件均不符合,则打开一个新的URL窗口

第1点和第3点使用以下SW代码。

出于某种原因,第2点不起作用。 client.navigate()承诺被拒绝:

Uncaught (in promise) TypeError: Cannot navigate to URL: http://localhost:4200/tasks/-KMcCHZdQ2YKCgTA4ddd

我认为这可能是由于缺少https,但从我的阅读中看来,似乎localhost在使用SW开发时被列入白名单。

火力的消息传递-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);
      }
    })
  );

});

我的SW代码绝大部分来自: https://gist.github.com/vibgy/0c5f51a8c5756a5c408da214da5aa7b0

2 个答案:

答案 0 :(得分:4)

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

您正在执行的WindowClient可能没有当前的服务工作者作为其活动服务工作者。根据{{​​3}}中的第4项:

  

如果上下文对象的关联服务工作者客户端处于活动状态   service worker不是上下文对象的相关全局对象   服务工作者,返回以TypeError拒绝的承诺。

如果您确定客户当前由服务工作人员控制时可以重现此问题,那么可能还会有其他事情发生,但这就是我尝试作为第一步。

答案 1 :(得分:1)

这对我有用:

1-创建一个可观察对象,并确保在解析消息传递API之前不要调用它。

2-自己注册服务工作者,然后首先检查其是否已经注册

3-调用event.waitUntil(clients.claim());在您的服务人员中

private isMessagingInitialized$: Subject<void>;

constructor(private firebaseApp: firebase.app.App) {
    navigator.serviceWorker.getRegistration('/').then(registration => {
        if (registration) {
            // optionally update your service worker to the latest firebase-messaging-sw.js
            registration.update().then(() => { 
                firebase.messaging(this.firebaseApp).useServiceWorker(registration);
                this.isMessagingInitialized$.next();
            });
        }
        else {
            navigator.serviceWorker.register('firebase-messaging-sw.js', { scope:'/'}).then(
                registration => {
                    firebase.messaging(this.firebaseApp).useServiceWorker(registration);
                    this.isMessagingInitialized$.next();
                }
            );

        }
    });
    
    this.isMessagingInitialized$.subscribe(
        () => {
            firebase.messaging(this.firebaseApp).usePublicVapidKey('Your public api key');
            firebase.messaging(this.firebaseApp).onTokenRefresh(() => {
                this.getToken().subscribe((token: string) => {

                })
            });
            firebase.messaging(this.firebaseApp).onMessage((payload: any) => {

            });
        }
    );
}
  • firebase-messaging-sw.js

      self.addEventListener('notificationclick', function (event) {
    
      event.notification.close();
    
      switch (event.action) {
          case 'close': {
              break;
          }
          default: {
              event.waitUntil(clients.claim());// this 
              event.waitUntil(clients.matchAll({
                  includeUncontrolled: true,
                  type: "window"
              }).then(function (clientList) {
              ...
              clientList[i].navigate('you url');
              ...
              }
          }
      }
    

    }