使用iOS 16.4,苹果已为安装的PWA添加了推送通知。但是,您可能已经注意到,iOS推送订阅似乎是在3次推送通知后自动终止的。
您发送通知,然后发送一秒钟,然后发送三分之一。一切都很好。但是,在发送第四次时,一切都会破裂。
好吧,好消息是它很容易修复!
tl; dr:这是您的推动实现的问题。
当然,正确实施时,推送订阅永远不会自动终止。这将破坏该功能的全部目的!
(旁注:如果您不想打扰这些无聊的技术实施详细信息,请继续注册Progressier)。
如何修复在iOS Safari上终止的推送订阅
当您向订阅的用户发送推送通知时,匹配域的服务工作者会启动推动事件。您服务工作者中的push event handler负责向用户显示通知。
但是,许多实施缺少的一个非常重要的细节是,您的活动处理程序必须在活动本身终止之前绝对显示通知。
使用registration.showNotification()显示通知。此功能返回一旦向用户显示了通知后解决的承诺。
几乎所有由Safari终止的推送订阅案例都可以通过缺少event.waitUntil()的推动事件处理人员来解释。这是一个普遍的问题。甚至sample code on MDN也包含了这个问题:
不正确:
self.addEventListener("push", function(e){
self.registration.showNotification(e.data.title, e.data);
});
如果您使用上面的示例代码,从长远来看,推送通知将无法正常工作,因为registration.showNotification()返回的承诺通常会在推送事件处理程序完成后解决。
也不正确:
self.addEventListener("push", async function(e){
await self.registration.showNotification(e.data.title, e.data);
});
使活动听众异步并等待registration.showNotification()承诺能够解决看起来像是一个非常诱人的解决方案。但是您仍然会遇到相同的问题。
这就是为什么:您的活动处理程序不足以等待工作完成。您必须主动告诉服务工作者事件本身需要考虑完成的工作。这是违反直觉的,因为您很少(如果有的话?)在客户端或服务器端逻辑中看到这种行为。
正确:
self.addEventListener("push", function(e){
event.waitUntil(
self.registration.showNotification(e.data.title, e.data)
);
});
这是一个简化的示例。在大多数情况下,您的代码将在调用registration.showNotification()之前做其他一些事情。只要记住要包装event.waitUntil()中的最后一点,并记住event.waitUntil()期望承诺(而不是函数)作为参数。
那么,如果我的实施是错误的,为什么推动通知在其他浏览器中有效呢?
这是因为一个称为无声推动的概念。当浏览器收到通知但未能向用户显示(或以延迟延迟)时,会发生A 静音推送。
当您省略event.waitUntil()时,Safari认为通知为a silent push ,因为事件在显示通知之前终止(即使在此后不久显示)。
)。无声的推动被整个底盘皱眉。实际上,当您register a push subscription时,所有浏览器都要求您将其配置为userVisibleOnly,这意味着您保证您只会发送通知,您将实际显示给用户。
这是一种安全措施,可防止应用程序在后台工作,而无需用户知道。如果您不小心在Safari上进行3次,则推动订阅将被取消。任何进一步的尝试都会导致错误。
其他浏览器的处理方式不同。例如,Chrome不会使推送订阅无效,因此,只要您在事件处理程序终止之前致电registration.showNotification(),您就可能绕过Chrome的 aintimelent-push 安全措施(这是显示默认值 This site has been updated in the background 通知)。
多年来似乎在许多应用程序中起作用的东西总是错误的。许多开发人员声称苹果发布了不良的推动实施 - 但这不是这里发生的事情。苹果的实施可以说,苹果的实施比Google更接近W3C specs。如果您的设置在其他浏览器中起作用,则本质上是因为...您能够偶然避免问题。无论如何,现在正确实施event.waitUntil()。您将消除定时随机性并使您的实现更加防前。
就是我!希望现在您知道如何在3次推送通知后取消推送订阅。如果您有任何疑问,请随时与我联系here。