iOSの通知は、通知が抑制されるとプッシュ権限を失う可能性があります。Discourseのコードは、オプションで通知を抑制するように構成されており、これが3回発生するとプッシュ権限を失います。
以下は、プッシュ通知サービスワーカーのコードです。
このコードには、178行目に重大なバグがあります。そこで、サービスワーカーはユーザーがアクティブかどうか(つまりアイドル状態でないか)をチェックします。その場合、通知を表示せずにプッシュイベントはfalseを返します。
(payload.hide_when_activeもチェックしますが、hide_when_activeは常にtrueであることが判明したため、ユーザーがアクティブな場合、このコードは常にfalseを返します。)
Appleはサイレントプッシュを禁止しており、通知が表示されないイベントが3回発生するとプッシュ権限が取り消されます
これは、プッシュ通知に関するAppleの規則では許容されません。
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
プッシュのサブスクライブをリクエストしたときに、JavaScriptが常にユーザーに表示されることを約束したことを思い出してください。これは、各プッシュに応答して常にプラットフォームネイティブ通知を表示する必要があることを意味します。プッシュイベントハンドラーでできるだけ早くこれを行うのが最善です。
…そして13:35で:
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
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を呼び出す必要があり、できるだけ早く行う必要があります。