# ユーザーがアクティブな場合、iOS通知はプッシュ許可を失う可能性があります

**URL:** https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225
**Category:** Bug
**Created:** [2024 年 1 月 1 日午後 11:35 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225 "2024-01-01T23:35:49Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![dfabulich](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dfabulich/32/108716_2.png) [@dfabulich](https://meta.discourse.org/u/dfabulich)
#### Post date: [2024 年 1 月 1 日午後 11:35 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/1 "2024-01-01T23:35:49Z")

</div>

iOSの通知は、通知が抑制されるとプッシュ権限を失う可能性があります。Discourseのコードは、オプションで通知を抑制するように構成されており、これが3回発生するとプッシュ権限を失います。

以下は、プッシュ通知サービスワーカーのコードです。

> <https://github.com/discourse/discourse/blob/baa7c4cec742f2275e5c8712c692076df0bfbac2/app/assets/javascripts/service-worker.js.erb#L176-L193>

このコードには、178行目に重大なバグがあります。そこで、サービスワーカーはユーザーがアクティブかどうか（つまりアイドル状態でないか）をチェックします。その場合、通知を表示せずにプッシュイベントはfalseを返します。

（`payload.hide_when_active`もチェックしますが、`hide_when_active`は[_常にtrue_](https://github.com/search?q=repo%3Adiscourse%2Fdiscourse%20hide_when_active&type=code)であることが判明したため、ユーザーがアクティブな場合、このコードは常にfalseを返します。）

# Appleはサイレントプッシュを禁止しており、通知が表示されないイベントが3回発生するとプッシュ権限が取り消されます

これは、プッシュ通知に関するAppleの規則では許容されません。

[https://webkit.org/blog/12945/meet-web-push/](https://webkit.org/blog/12945/meet-web-push/)

> ## 電力とプライバシー
> 
> WebKitオープンソースプロジェクトとAppleは、プライバシーを基本的な人権として扱っています。Webプラットフォームの他の特権機能と同様に、プッシュサブスクリプションをリクエストするには、明示的なユーザー操作が必要です。また、`userVisibleOnly`フラグをtrueに設定し、プッシュメッセージに応答して常に通知を表示することで、その約束を果たす必要があります。
> 
> Web Push APIは、サイレントバックグラウンドランタイムの招待ではありません。それはユーザーの信頼を損ない、ユーザーのバッテリー寿命に影響を与える可能性があるためです。
> 
> **`userVisibleOnly`の約束の違反は、プッシュサブスクリプションの取り消しにつながります。**

（私の強調）

これは、AppleのWWDCビデオ「Web Pushes」の9:57でさらに詳しく説明されています。

[https://developer.apple.com/videos/play/wwdc2022/10098/?time=596](https://developer.apple.com/videos/play/wwdc2022/10098/?time=596)

> プッシュのサブスクライブをリクエストしたときに、JavaScriptが常にユーザーに表示されることを約束したことを思い出してください。これは、各プッシュに応答して常にプラットフォームネイティブ通知を表示する必要があることを意味します。プッシュイベントハンドラーでできるだけ早くこれを行うのが最善です。

…そして13:35で：

[https://developer.apple.com/videos/play/wwdc2022/10098/?time=814](https://developer.apple.com/videos/play/wwdc2022/10098/?time=814)

> プッシュサブスクリプションをリクエストする方法のコードを示したときに言及したように、プッシュがユーザーに表示されることを約束する必要があります。プッシュイベントを処理することは、JavaScriptがサイレントバックグラウンドランタイムを取得するための招待ではありません。そうすることは、ユーザーの信頼とユーザーのバッテリー寿命の両方を損なうことになります。プッシュイベントを処理する場合、実際にはNotification Centerに通知を投稿する必要があります。他のブラウザは、プッシュをユーザーに表示するという約束に違反することに対する対策をすべて講じており、Safariも同様です。macOS Venturaのベータ版では、 **通知を適時に投稿できなかった3回のプッシュイベントの後、サイトのプッシュサブスクリプションは取り消されます** 。再度、権限ワークフローを通過する必要があります。

（私の強調）

# Appleは通知を閉じた後ではなく、すぐに通知を表示することを推奨しています

Appleが推奨するコードは、11:39で次のようになっています。

[https://developer.apple.com/videos/play/wwdc2022/10098/?time=699](https://developer.apple.com/videos/play/wwdc2022/10098/?time=699)

```js
self.addEventListener('push', (event) => {
    let pushMessageJSON = event.data.json();

    // Our server puts everything needed to show the notification
    // in our JSON data.
    event.waitUntil(self.registration.showNotification(pushMessageJSON.title, {
        body: pushMessageJSON.body,
        tag: pushMessageJSON.tag,
        actions: [{
            action: pushMessageJSON.actionURL,
            title: pushMessageJSON.actionTitle,
        }]
    }));
}

```

> プッシュをサブスクライブしたときに、JavaScriptが常にユーザーに表示されることを約束したことを思い出してください。これは、各プッシュに応答して常にプラットフォームネイティブ通知を表示する必要があることを意味します。プッシュイベントハンドラーでできるだけ早くこれを行うのが最善です。

Discourseのコードは、推奨されるベストプラクティスに従っていません。Discourseのコードは、まずすべての通知を閉じ、その後通知を表示します。

Discourseは、プッシュイベントに応答して常に`showNotification`を呼び出す必要があり、できるだけ早く行う必要があります。

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [2024 年 1 月 1 日午後 11:46 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/2 "2024-01-01T23:46:51Z")

</div>

@Falco / @featheredtoast これについてどう思いますか？

終了チェックとアイドルチェックの両方を削除した場合、どのような影響がありますか？

全体として、このアイドルチェックについてはまったく確信が持てず、混乱を招くだけのように感じます。

最悪の場合、AndroidまたはDesktop（Safari以外）でこれを **必須** とする場合は、ここに条件を追加することができますが、私の感覚では、単にコードを削除すべきです。

素晴らしいデバッグです @dfabulich 🤗

---

<div class="post-metadata">

### Author: ![dfabulich](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dfabulich/32/108716_2.png) [@dfabulich](https://meta.discourse.org/u/dfabulich)
#### Post date: [2024 年 1 月 1 日午後 11:56 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/4 "2024-01-01T23:56:04Z")

</div>

`showNotification` を呼び出した _後_ であれば、通知を閉じることは問題ない、ということですね。\n\n…しかし、通知を閉じることの必要性が全く理解できません。通知トレイに溜めておいても良いのではないでしょうか。\n\n[https://developer.mozilla.org/en-US/docs/Web/API/Notification/close\n\n](https://developer.mozilla.org/en-US/docs/Web/API/Notification/close%5Cn%5Cn)\> **注意:** このAPIは、単に一定時間後に通知を画面から削除するために使用すべきではありません。このメソッドは通知トレイからも通知を削除するため、ユーザーが最初に表示された通知を操作できなくなります。このAPIの有効な使用例としては、もはや関連性のない通知を削除することです（例：メッセージアプリの場合、ユーザーがすでにウェブページで通知を読んだ場合や、音楽アプリで次の曲がすでに再生されている場合）。

---

<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: [2024 年 1 月 2 日午前 12:44 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/5 "2024-01-02T00:44:52Z")

</div>

この週末にこの件について読んだことから、プッシュイベントハンドラでasync/promisesを使用することさえできないことがわかりました。すぐに表示しないと、Appleは通知権限を剥奪します。

これはすべて、@dfabulichが言っていることと一致しています。

> [@sam](#):
>
> 終了チェックとアイドルチェックの両方を削除した場合、どのような影響がありますか？

ここでは「賢すぎる」のだと思います。すべてのチェックを削除して、通知を表示するだけでよいはずです。

---

<div class="post-metadata">

### Author: ![WorldIsMine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/worldismine/32/455660_2.png) [@WorldIsMine](https://meta.discourse.org/u/WorldIsMine)
#### Post date: [2024 年 1 月 2 日午後 8:02 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/6 "2024-01-02T20:02:24Z")

</div>

@dfabulich、これを発見してくれて本当にありがとう！

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [2024 年 1 月 3 日午前 12:31 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/7 "2024-01-03T00:31:31Z")

</div>

はい、これに対するPRがあります。

@Falco / @featheredtoast これをマージすべきでしょうか？

> <https://github.com/discourse/discourse/pull/25099>
>
> According to Apple, silent push notifications are automatically punished per:
> 
> h…ttps://developer.apple.com/videos/play/wwdc2022/10098/?time=814
> 
> \> As mentioned when I showed you the code on how to request a push
> \> subscription, you must promise that pushes will be user visible.
> \> Handling a push event is not an invitation for your JavaScript to
> \> get silent background runtime. Doing so would violate both a user’s
> \> trust and a user’s battery life. When handling a push event, you are
> \> in fact required to post a notification to Notification Center.
> \> Other browsers all have countermeasures against violating the promise
> \> to make pushes user visible, and so does Safari.
> \> In the beta build of macOS Ventura, after three push events where you
> \> fail to post a notification in a timely manner, your site’s push
> \> subscription will be revoked. You will need to go through the permission
> \> workflow again.
> 
> The isIdle check was causing certain push notifications to be silent
> 
> Additionally, the auto dismissal logic was causing delays which may cause
> the device to think the push was a silent one.
> 
> By removing this we hope to ensure push notification delivery is more robust
> and consistent on iOS.

プッシュ通知をスキップする必要がある場合は、クライアントではなくサーバーで行う必要があります。折りたたみロジックは常にいくらか疑問があり、アプリは通常それを実行しません。

---

<div class="post-metadata">

### Author: ![featheredtoast](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/featheredtoast/32/116994_2.png) [@featheredtoast](https://meta.discourse.org/u/featheredtoast)
#### Post date: [2024 年 1 月 3 日午前 1:01 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/8 "2024-01-03T01:01:42Z")

</div>

確かに、通知を表示する必要がある場合にのみプッシュする方がはるかに理にかなっています。最終的には他の場所での過剰な通知を抑制すべきですが、ここではマージしても問題ありません 👍

通知の折りたたみについてですが、失われるのは残念ですが…理想的には、ログイン中のデバイスで通知を確認していくにつれて、他のアプリのように自動的に消去できるようにしたいですが、それには追加の労力がかかるかもしれません。ここでの意図は、古い通知が積み重なるのを防ぐという点では同じです。これも問題ありませんが、後でどれだけ問題を引き起こすかによって、再検討する必要があります。

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [2024 年 1 月 8 日午前 7:58 UTC](https://meta.discourse.org/t/ios-notifications-can-lose-permission-to-push-if-the-user-is-currently-active/290225/11 "2024-01-08T07:58:49Z")

</div>


