iOS PWA のプッシュ通知購読が SW によるアプリ制御不足により静かに失敗する

こんにちは :waving_hand:

iOS PWA でのプッシュ通知の設定時に、奇妙な動作(おそらくバグ)が発生しました。UI はプッシュ通知のサブスクリプションが設定されたかのように動作しますが、実際にはバックグラウンドで何も起きておらず、ユーザーは決してプッシュ通知を受け取ることができません。

(tl;dr: 修正方法がわかり、PR を提供できます)

再現手順 :footprints:

問題は、iOS で PWA をインストールした直後にプッシュ通知を有効にしようとする際のものです。

  1. iOS のモバイル Safari で Discourse インスタンスを開きます
  2. 共有メニューを開き、「ホーム画面に追加」を選択します
  3. ホーム画面の新しい PWA を開きます
  4. プッシュ通知の有効化を問うバナーが表示されます
  5. 「通知を有効にする」リンクをクリックします
    1. システムダイアログ “xyz”が通知を送信しようとしています が表示されるので、承認します。
  6. 通知設定に移動すると、ライブ通知無効 になっていることがわかります。
    1. サーバーを確認しても、ユーザーの新しい PushSubscription レコードは見つかりません。

期待される動作 :books:

ステップ 5 の後、通知が有効になったことを示すプッシュ通知が既に届いているはずです。また、データベースには現在のユーザーの新しい PushSubscription レコードが存在し、PWA での ライブ通知 受信設定が有効になっている必要があります。

問題点 :bug:

直ちに起動したばかりの PWA では、サービスワーカーはインストールされアクティブ化されていますが、まだページを制御していません。そのため、lib/push-notifications.js 内の isPushNotificationsSupported() チェックは、navigation.serviceworker.controllernull を返すため、false を返してしまいます。重要な 2 行は以下の通りです。

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

これにより、UI はユーザーに対して設定に問題がないかのように示唆しますが、実際にはプッシュ通知は決して届きません。

最初の読み込み時、PWA は制御されておらず、ユーザーが許可を与えたにもかかわらず subscribe() の呼び出しが行われません… :bug:

ユーザー自身が問題を知っていれば、以下のように修正できます。

  1. PWA を完全に終了します(スワイプして消去…)
  2. PWA を再度開きます
  3. 通知設定に移動します
  4. ライブ通知 を再度有効にします
  5. → 今回は、新しい PushSubscription レコードが作成され、通知設定が完了します。

潜在的な修正策 :adhesive_bandage:

私はこの問題を回避するために、インストール/アクティブ化時に skipWaiting()clients.claim() を呼び出す別のサービスワーカーを登録することで対応しました。これにより、即座に PWA の制御を引き継ぎ、サブスクリプションが正常に完了し、対応する PushSubscription レコードが作成されます。

これはカスタムプラグインの一部として「ホットフィックス」としてデプロイしており、Discourse コアをフォークせずにユーザーの状況を修正できました。

変更点は 2 つだけです。

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

ただし、この修正は Discourse コアに含めるべきだと考えています。現状では、プラグインが不要に PWA の制御を引き継いでしまっています。サブスクライブが実際に機能するように Discourse コア内のチェックを調整する PR を提供できます。ここで議論したいと思いますが、すでにこのトピックに関するご意見をいただければ幸いです。

「いいね!」 1

Discourse コアへの修正を含む PR です → FIX: Allow push notification subscriptions on first launch of iOS PWA · Pull Request #39885 · discourse/discourse

これにより、サブスクリプションが静かに失敗しサーバーに到達しないという問題が解決します。ただし、完全に安全を確保するためには、まだ不足している点があります。それは、最初に受信したプッシュ通知が、アプリを制御するサービスワーカーなしではアプリ内でルーティングできず、ユーザーがアプリを再起動しない限り機能しないという点です。

これは私の PR に追加することも可能ですが、この修正が望ましいものかどうかは 100% 確信が持てません。

「いいね!」 1