删除Web推送通知

7

有没有一种方法可以在显示后删除Web推送通知?从设备的通知列表中删除它-或将其标记为“已读”?

我认为这不能从服务器上完成,我一直在寻找JavaScript API-但我没有找到任何内容。

(我试图解决的更广泛的问题是如何在多个屏幕/浏览器/设备上同步通知。)

3个回答

4

尽管无法撤销推送消息,但可以使用以下方法关闭一个:

// app.js
navigator.serviceWorker.ready.then(reg => {
  reg.getNotifications().then(notifications => {
    for (let i = 0; i < notifications.length; i += 1) {
      notifications[i].close();
    }
  });
});

你甚至可以通过载荷中的特殊操作从后端发送新的WebPush消息,例如data: { action: 'close', id: 123 },以触发关闭消息。'push'事件监听器可以将'message'事件传递给所有客户端,以关闭给定(或所有)打开的通知。
// sw.js
self.addEventListener('push', event => {
  let opts = event.data.json();

  if (opts.data && opts.data.action) {
    event.waitUntil(clients.matchAll().then(windowClients => {
      for (let i = 0; i < windowClients.length; i += 1) {
        windowClients[i].postMessage(opts.data);
      }
    });
  }
});

// app.js
navigator.serviceWorker.addEventListener('message', event => {
  if (event.data && event.data.action && event.data.action === 'close') {
    closeNotification(event.data.id);
  }
});

function closeNotification(id) {
  navigator.serviceWorker.ready.then(reg => {
    reg.getNotifications().then(n => {
      for (let i = 0; i < n.length; i += 1) {
        if (n[i].data && n[i].data.id && n[i].data.id === id) {
          n[i].close();
        }
      }
    });
  });
}

最大的缺点是该方法只适用于活跃/打开的客户端。我还没有找到解决这个问题的方法。
使用的来源:

1
这不是可行的解决方案,因为静默推送是不允许的:即当您发送推送消息时,必须显示通知 - 而仅关闭其他通知而不显示任何内容的消息将被视为静默推送。 - collimarco
@collimarco,你为什么认为静默推送不被允许并且必须总是显示通知?我的理解是,响应通知负载由您的应用程序处理,您不必强制执行任何操作,如果您不想要。只要您适当地使用event.waitUntil()等即可。 - Gary Green
@GaryGreen 请查看标准:PushManager.subscribe具有设置为true的userVisibleOnly选项,该选项是必需的。 - collimarco

1
我认为这可能是不可能的。您可以显示和隐藏通知。这可以作为默认浏览器操作的解决方法,如此处所述。

只有在接收到推送消息并且服务工作者中的推送事件在传递给event.waitUntil()的promise完成后没有显示通知时,Chrome才会显示“此站点已在后台更新。”通知。


1
我找到的最接近的解决方案是在通知显示后关闭它。以下是我拥有的代码解决方案。
event.waitUntil(
    self.registration.showNotification(title, options)
    .then(function (data) {
        self.registration.getNotifications()
        .then(function (notifications) {
            setTimeout(function () {
                //console.log(notifications);
                notifications.forEach(notification => notification.close())
            }, 10);
        })
    })
);

1
Service Worker 无法可靠地使用超时或间隔,因为浏览器会关闭 Service Worker 以节省系统资源。一个小的超时可能会起作用,但我不会依赖它,特别是对于较长时间。 - Scott
@Gavril,你为什么还要等待呢?我们能否立即关闭通知? - Surfer on the fall
setTimeout(function {}, duration); 的定义中,duration 是以毫秒为单位的。 - Serge Stroobandt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接