Chrome 推送通知:本站已在后台更新

Chrome Push Notification: This site has been updated in the background

在实施 chrome 推送通知时,我们正在从我们的服务器获取最新的更改。在这样做的同时,服务人员会显示一条带有消息

的额外通知

This site has been updated in the background

已尝试使用此处发布的建议 https://disqus.com/home/discussion/html5rocks/push_notifications_on_the_open_web/
但直到现在找不到任何有用的东西。有什么建议吗?

通常,一旦您收到来自 GCM(Google 云消息传递)的推送消息,您就必须在浏览器中显示推送通知。这在此处的第 3 点中提到:

https://developers.google.com/web/updates/2015/03/push-notificatons-on-the-open-web#what-are-the-limitations-of-push-messaging-in-chrome-42

因此,尽管您收到了来自 GCM 的推送消息,但您可能会以某种方式跳过推送通知,并且您收到的推送通知带有一些默认消息,例如 "This site has been updated in the background"。

简短回答:您应该使用 event.waitUntil 并向其传递承诺,最终 returns showNotification。 (如果你有任何其他嵌套的承诺,你也应该 return 它们。)

我遇到了同样的问题,但经过长时间的研究,我知道这是因为 PUSH 事件和 self.registration.showNotification() 之间发生了延迟。我只在 self.registration.showNotification()`

之前错过了 return 关键字

所以你需要实现以下代码结构来获取通知:

var APILINK = "https://xxxx.com";
 self.addEventListener('push', function(event) {
      event.waitUntil(
          fetch(APILINK).then(function(response) {
               
        return response.json().then(function(data) {
                  console.log(data);
                  var title = data.title;
                  var body = data.message;
                  var icon = data.image;
                  var tag = 'temp-tag';
                  var urlOpen = data.URL;

                return  self.registration.showNotification(title, {
                      body: body,
                      icon: icon,
                      tag: tag
                  })
              });
          })
      );
  });

最小场景:

self.addEventListener('push', event => {
  const data = event.data.json();
  event.waitUntil(
    // in here we pass showNotification, but if you pass a promise, like fetch,
    // then you should return showNotification inside of it. like above example.
    self.registration.showNotification(data.title, {
      body: data.content
    })
  );
});

我过去 运行 解决过这个问题。根据我的经验,原因通常是以下三个问题之一:

  1. 您没有显示响应推送的通知 信息。每次在设备上收到推送消息时, 您完成了事件的处理,通知必须保持可见 装置。这是由于使用 userVisibleOnly: true 选项进行订阅(但请注意,这不是可选的,也没有设置它 会导致订阅失败。
  2. 您没有调用 event.waitUntil() 来响应处理事件。应向此函数传递一个承诺,以指示浏览器在检查是否显示通知之前应等待承诺解决。
  3. 出于某种原因,您要在显示通知之前解决传递给 event.waitUntil 的承诺。请注意,self.registration.showNotification 是一个承诺和异步,因此您应该确保它在传递给 event.waitUntil 的承诺解决之前已解决。

这有效,只是 copy/paste/modify。将 "return self.registration.showNotification()" 替换为以下代码。第一部分是处理通知,第二部分是处理通知的点击。但是不要感谢我,除非你感谢我花几个小时在谷歌上搜索答案。

说真的,感谢 Matt Gaunt 在 developers.google.com

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  var title = 'Yay a message.';
  var body = 'We have received a push message.';
  var icon = 'YOUR_ICON';
  var tag = 'simple-push-demo-notification-tag';
  var data = {
    doge: {
        wow: 'such amaze notification data'
    }
  };

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag,
      data: data
    })
  );
});

self.addEventListener('notificationclick', function(event) {
  var doge = event.notification.data.doge;
  console.log(doge.wow);
});

如果您需要在接收推送通知事件时发生更多事情,showNotification() 返回 Promise。所以你可以使用经典的链接。

const itsGonnaBeLegendary = new Promise((resolve, reject) => {
    self.registration.showNotification(title, options)
        .then(() => {
            console.log("other stuff to do");

            resolve();
        });
});

event.waitUntil(itsGonnaBeLegendary);

我试图理解为什么 Chrome 有这样的要求,即 service worker 必须在收到推送通知时显示通知。我认为原因是推送通知服务人员即使在用户关闭网站选项卡后仍会在后台继续 运行。因此,为了防止网站在后台秘密 运行ning 代码,Chrome 要求它们显示一些消息。

What are the limitations of push messaging in Chrome?

...

  • You have to show a notification when you receive a push message.

...

Why not use Web Sockets or Server-Sent Events (EventSource)?

The advantage of using push messages is that even if your page is closed, your service worker will be woken up and be able to show a notification. Web Sockets and EventSource have their connection closed when the page or browser is closed.

我推送了两次通知,一次是在 FCM 的 onBackgroundMessage()

click_action: "http://localhost:3000/"

并在 self.addEventListener('notificationclick',...

中一次
 event.waitUntil(clients.matchAll({
        type: "window"
    }).then...

所以我评论了 click_action,ctrl+f5 刷新浏览器,现在可以正常使用了