# iOS PWA 中的推送通知订阅因 SW 未控制应用而静默失败

**URL:** <https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645>\
**Category:** Bug\
**Tags:** pwa, push-notifications, ios\
**Created:** [2026年五月11日 10:17 UTC](https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645 "2026-05-11T10:17:46Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![klappradla](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/klappradla/32/531604_2.png) [@klappradla](https://meta.discourse.org/u/klappradla)\
**Post date:** [2026年五月11日 10:17 UTC](https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645/1 "2026-05-11T10:17:47Z")

</div>

你好 👋

我们在 iOS PWA 设置推送通知时遇到了一些奇怪的行为（或者可能是一个 bug……）。界面显示推送通知订阅已设置，但后台实际上没有任何操作发生，用户将永远无法收到任何推送通知。

_(tl;dr：我想我知道如何修复它，并可以提供 PR)_

## 复现步骤 👣

问题在于在 iOS 上安装 PWA 后立即启用推送通知。

1. 在 iOS 的 Mobile Safari 中打开你的 Discourse 实例
2. 打开分享菜单并选择“添加到主屏幕”
3. 在主屏幕上打开新的 PWA
4. 你会看到一个横幅，询问你是否要启用推送通知
5. 点击“启用通知”链接
  1. 你会看到系统对话框 `“xyz”想要向你发送通知` - 点击允许。

6. 导航到你的通知偏好设置，你会看到 `实时通知` **未启用** 。
  1. 在服务器端检查，你也找不到该用户的任何新 `PushSubscription` 记录。

## 预期行为 📚

在第 5 步之后，你应该已经收到一条通知，提示通知已启用。数据库中应该已经为你的当前用户创建了一条新的 `PushSubscription` 记录，并且他们在 PWA 中接收 `实时通知` 的设置应该已启用。

## 问题 🐛

在刚启动的 PWA 中，服务 Worker 已安装并激活，但 **尚未控制页面** 。因此，`lib/push-notifications.js` 中的 `isPushNotificationsSupported()` 检查仍会返回 false，因为 `navigator.serviceWorker.controller` 返回 `null`。以下是关键的两行代码：

```javascript
navigator.serviceWorker.controller &&
navigator.serviceWorker.controller.state === "activated"

```

这导致界面让用户以为一切正常，但他们实际上永远收不到任何推送通知。

在首次加载时，PWA 处于未受控状态，即使用户已授予权限，`subscribe()` 调用也从未执行……🐛

如果用户知道如何操作，他们可以自行修复此问题：

1. 完全关闭 PWA（将其从后台划掉……）
2. 重新打开 PWA
3. 进入通知偏好设置
4. 再次启用 `实时通知`
5. → 这次应该会创建一条新的 `PushSubscription` 记录，通知设置成功。

## 潜在修复方案 🩹

我通过注册另一个服务 Worker 来绕过此问题，该 Worker 在安装/激活时调用 `skipWaiting()` 和 `clients.claim()`。这样做可以立即接管对 PWA 的控制权，订阅得以成功执行，并创建相应的 `PushSubscription` 记录。

我已将此作为“热修复”部署到我的某个自定义插件中，这样我就可以在不深入修改 Discourse 核心代码的情况下修复用户的问题……

只需进行两处更改：

```ruby
# plugin.rb
register_service_worker "push-notification-setup.js"

```

```javascript
// assets/push-notification-setup.js
self.addEventListener("install", function () {
  self.skipWaiting();
});
		
		
self.addEventListener("activate", function (event) {	
  event.waitUntil(self.clients.claim());
});

```

不过，我认为这个修复应该直接集成到 Discourse 核心中。目前这样做，插件会不必要地接管对 PWA 的控制。我可以提供一个 PR，相应地调整 Discourse 核心中的检查逻辑，使订阅功能真正生效。我在这里等待反馈，也欢迎大家就此话题发表意见。

---

<div class="post-metadata">

**Author:** ![klappradla](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/klappradla/32/531604_2.png) [@klappradla](https://meta.discourse.org/u/klappradla)\
**Post date:** [2026年五月11日 12:49 UTC](https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645/2 "2026-05-11T12:49:23Z")

</div>

这是针对 Discourse 核心的修复 PR → [FIX: Allow push notification subscriptions on first launch of iOS PWA - Pull Request #39885 - discourse/discourse - GitHub](https://github.com/discourse/discourse/pull/39885)

它解决了此处描述的问题，即订阅静默失败且无法到达服务器。但为了确保绝对安全，目前仍缺少的是：在服务进程控制应用之前，首次收到的推送通知将无法在应用内部进行路由，因此需要用户重启应用。

我也可以在现有 PR 的基础上添加这一功能。但我还不能完全确定该修复方案是否符合预期。

---

<div class="post-metadata">

**Author:** ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)\
**Post date:** [2026年五月11日 17:45 UTC](https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645/3 "2026-05-11T17:45:43Z")

</div>

> [@klappradla](#):
>
> 我通过注册另一个服务工作者（Service Worker）并调用 `skipWaiting()` 和 `clients.claim()` 来绕过了这个问题。

你能否提交一个 PR，将这些代码添加到我们的主服务工作者中？这应该能解决这个问题，对吧？

这样做有什么困难吗？

---

<div class="post-metadata">

**Author:** ![klappradla](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/klappradla/32/531604_2.png) [@klappradla](https://meta.discourse.org/u/klappradla)\
**Post date:** [2026年五月12日 07:48 UTC](https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645/4 "2026-05-12T07:48:08Z")

</div>

好的。我看看那会怎样，会更新 PR，准备好后告诉你。

---

<div class="post-metadata">

**Author:** ![klappradla](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/klappradla/32/531604_2.png) [@klappradla](https://meta.discourse.org/u/klappradla)\
**Post date:** [2026年五月12日 09:29 UTC](https://meta.discourse.org/t/push-notification-subscription-in-ios-pwa-silently-failing-because-of-sw-not-controlling-the-app/402645/5 "2026-05-12T09:29:09Z")

</div>

我已更新 [我的 PR](https://github.com/discourse/discourse/pull/39885)，以确保 Service Worker 能立即控制 PWA。

我觉得我还需要在不同部署环境中再做几项测试。不过，或许你现在就可以先 👀 一下？
