Chrome:Serviceworker 在接收推送消息时不会转换到运行状态

问题描述

我们已经实施了一个 SDK,以简化发送和接收推送通知的过程。但是,最近我们遇到了一个问题,即每次发送推送消息时都会收到Generic Notification(即此站点已在后台更新)消息。

经过一段时间的检查和反复试验,我们得出了一个粗略的结论:

  • 每当我们发送推送通知时,第一次,Service Worker 不会唤醒并挂在 Stopped 状态。结果显示Generic Notification。在紧接的后续推送消息中,服务工作线程转换为 Running 状态并接收推送消息。
  • 以下负责处理 push 事件的代码不会在第一次发送推送消息时调用
@serviceWorkerEvent('push')
    public static async onPushEvent(context: Context,event: PushEvent) {
        context.api.pushDelivered({
            // Sending Analytics
        }).catch(e => log.error('e'));

        const notificationoptions: Notificationoptions = {
            // Notification Options
        };

        const notifTitle = notificationData.title || '';
        await (await context.serviceWorker.registration).showNotification(notifTitle,notificationoptions);

        await context.workerMessenger.broadcast(WORKER_MESSAGE_TYPES.PUSH_RECEIVED,notificationData);
    }

附言使用包含 event.waitUntil() 的包装函数,我们正在等待里面的 promise 得到解决

解决方法

这是预期的行为。您的 Service Worker 没有处理第一个 push 事件,因为您的页面仍然是它的不受控制的客户端。您的 Service Worker 尚未处于 active 状态。

来自The Service Worker Lifecycle(强烈推荐阅读):

在成功完成安装并变为“活动”状态之前,Service Worker 不会收到诸如 fetch 和 push 之类的事件。

要处理第一个 push 事件,您可以:

  1. 在您的 Service Worker 注册脚本中调用 location.reload()
  2. 在您的 Service Worker 中调用 clients.claim()

选项 2 覆盖了 Service Worker 的默认行为,让它控制不受控制的客户端(您的 sw 立即声明客户端)。

另见: