メインコンテンツへスキップ
重複通知とは、同じデバイスが同じメッセージ内容を複数回受け取ることです。このガイドでは、最も一般的な原因とその解決方法を説明します。 同じユーザーが複数のデバイス(スマートフォン、タブレット、デスクトップ)で通知を受け取る場合、それはターゲット設定(セグメント、外部 ID など)に基づく想定どおりの動作です。重複するアプリ内メッセージについては、アプリ内メッセージのトラブルシューティングガイドを参照してください。
Apple は、iOS 17 で重複を引き起こすバグを認めました。これは iOS 17.3 で修正されました。詳細はこちら

まずここから

状況に最も合うセクションを選択してください:

同じメッセージが複数回送信される

重複通知の最も一般的な原因は、OneSignal API 経由で同じ通知ペイロードを複数回送信することです。一般的な理由:
  • サーバーが最初のリクエストが成功したかどうかを確認せずにリクエストを再試行します。
  • バックエンドパイプラインのロジックが同じ通知を 2 回送信しています。
  • OneSignal に移行中だが、以前のプロバイダーからまだ通知を送信している。両方のシステムから同時に送信しないでください。

冪等 API リクエスト

再試行時に冪等キーを再利用することで重複メッセージを防止します。

サードパーティ通知ハンドラー

アプリ内の他のコードが OneSignal のプッシュペイロードを処理し、OneSignal に加えて独自の通知を表示する場合に重複が発生します。これには以下が含まれます:
  • 同じペイロードを受信する他のリモートプッシュ SDK(例:Firebase Cloud Messaging)。
  • Android の FirebaseMessagingService や iOS の UNUserNotificationCenterDelegate などのカスタムメッセージハンドラーが受信ペイロードを読み取り、ローカル通知を構築する場合。
OneSignal SDK は、唯一のハンドラーである場合に OneSignal ペイロードを自動的にフィルタリングします。サードパーティのコードは、明示的に指定しない限りフィルタリング方法を知りません。

OneSignal 通知の識別

すべての OneSignal 通知には、OneSignal 通知 UUID を含む i キーを持つ custom オブジェクトが含まれます:
JSON
{
  "custom": {
    "i": "the-notification-id"
  }
}
完全なペイロードリファレンスについては、カスタム OneSignal ペイロード構造を参照してください。

サードパーティハンドラーから OneSignal 通知をフィルタリングする

OneSignal 以外のすべてのハンドラーで、custom.i キーを確認し、存在する場合は早期リターンします。OneSignal は自身のペイロードを処理し、他のコードは独自のペイロードの処理を続けます。
カスタム FirebaseMessagingService または他のリモートメッセージハンドラーで:
Kotlin
override fun onMessageReceived(remoteMessage: RemoteMessage) {
    val customJson = remoteMessage.data["custom"]
    if (customJson != null) {
        try {
            val custom = JSONObject(customJson)
            if (custom.has("i")) {
                // OneSignal 通知——OneSignal SDK に処理を任せる
                return
            }
        } catch (e: JSONException) {
            // OneSignal ペイロードではないため、処理を続行する
        }
    }

    // ここで独自の通知を処理する
}
他のプロバイダーから送信されるペイロード構造を制御できる場合は、独自のマーカーキー(例:my_app_notification: true)を追加し、双方向でフィルタリングしてください——自分のコードではマーカーを含む通知のみを処理し、OneSignal には custom.i キーを含む通知を処理させます。

Android 通知ハンドラー

OneSignal は、通知が表示される前に傍受してカスタマイズできる 2 つの Android コールバックを提供します: これらのコールバックが OneSignal の自動表示に加えて通知を表示すると、重複が発生します。

preventDefault()display() のルール

OneSignal は、event.preventDefault() で抑制しない限り、各通知を自動的に表示します。2 つのよくある間違いが重複を引き起こします:
  • 最初に event.preventDefault() を呼び出さずに event.getNotification().display() を呼び出す——通知が 2 回表示されます。
  • OneSignal がオリジナルを表示している間に NotificationManagerCompat.notify() で別の通知を投稿する。
アクティブな表示パスは 1 つのみにする必要があります——OneSignal の display() か、独自の NotificationManagerCompat.notify() のどちらか一方のみで、両方は使用しないでください。
override fun onNotificationReceived(event: INotificationReceivedEvent) {
    event.preventDefault()

    val notification = event.notification
    notification.setExtender { builder ->
        builder.setColor(0xFF0000FF.toInt())
    }
    notification.display()
}
同じルールがフォアグラウンドライフサイクルリスナーの onWillDisplay にも適用されます:
Kotlin
OneSignal.Notifications.addForegroundLifecycleListener(object : INotificationLifecycleListener {
    override fun onWillDisplay(event: INotificationWillDisplayEvent) {
        event.preventDefault()

        // 独自の UI をレンダリングするか、event.notification.display() を呼び出して OneSignal 通知を表示する
    }
})
preventDefault() を呼び出しても display() を呼び出さない場合、通知は静かに破棄され、ユーザーには表示されません。すべてのコードパスが display() をちょうど 1 回呼び出すか、意図的に通知を抑制するようにしてください。
通知サービス拡張機能とフォアグラウンドライフサイクルリスナーの両方を使用する場合は、特定のアプリ状態に対してどちらか一方のハンドラーのみが通知を表示するようにしてください。両方から display() を呼び出すと重複が発生します。

コールバック内の非同期処理

表示前にバックグラウンド処理(ネットワーク呼び出し、データベース検索)を行う場合は、コールバック内で同期的に preventDefault() を呼び出し、非同期処理が完了した後にのみ display() を呼び出してください。preventDefault() なしでコールバックから戻ると OneSignal が通知を表示してしまい、その後に display() を呼び出すと重複が発生します。

iOS フォアグラウンドハンドラー

OneSignal は、SDK の初期化時に自身を UNUserNotificationCenterDelegate として設定します。アプリがフォアグラウンド通知処理も実装している場合、通知が 2 回表示される可能性があります——OneSignal からの 1 回とコードからの 1 回です。 重複を引き起こす一般的なパターン:
  • OneSignal への呼び出しを転送せずに独自の UNUserNotificationCenterDelegate を実装し、同じメソッドから completionHandler([.banner, .sound]) を呼び出してカスタムアプリ内アラートを表示する。
  • OneSignal も表示している受信プッシュに応答してローカル通知(UNUserNotificationCenter.current().add(...))をスケジュールする。
重複を引き起こさずにフォアグラウンド表示を制御するには、OneSignal のフォアグラウンドライフサイクルリスナーを使用し、自分で通知をレンダリングしたい場合に event.preventDefault() を呼び出してください:
Swift
OneSignal.Notifications.addForegroundLifecycleListener(self)

func onWillDisplay(event: OSNotificationWillDisplayEvent) {
    event.preventDefault()

    // 独自の UI をレンダリングするか、event.notification.display() を呼び出して OneSignal 通知を表示する
}

複数のアプリインスタンス

アプリの本番バージョンと開発バージョンの両方がインストールされている場合、重複が発生する可能性があります。各アプリには一意のパッケージ名があり、独自のプッシュトークンを受け取ります。通知を長押しして、どのアプリインスタンスから送信されたかを確認します。

診断のヒント

重複問題のデバッグを迅速に行うために、次の情報を収集して OneSignal サポートに送信してください:
  • 重複を受け取ったデバイスの OneSignal サブスクリプション ID
  • OneSignal メッセージ ID またはダッシュボード内のメッセージへのリンク
  • アプリ内の他のライブラリまたはプラグインのリスト
  • 問題を再現するデバッグログ
  • 詳細な再現手順

FAQ

アプリに 2 つの通知 SDK がある場合はどうなりますか?

両方の SDK が同じ通知を独立して処理・表示する可能性があります。OneSignal は自身の通知を自動的にフィルタリングしますが、他の SDK はフィルタリングしません。custom.i キーを確認することで、他の SDK のハンドラーから OneSignal ペイロードをフィルタリングしてください。コード例については、サードパーティ通知ハンドラーを参照してください。

以前のプロバイダーと OneSignal から同時にプッシュを送信するには?

段階的に移行できますが、両方のプロバイダーから同じメッセージを送信しないようにしてください。
  • Android:OneSignal を統合してアプリをリリースする際に、古い SDK の通知処理コードを削除します。ユーザーが更新すると、古いプロバイダーからのプッシュを受信しなくなります。
  • iOS:ユーザーが更新している間、一時的に古いプロバイダーから送信を続けることができます。完全に移行したら、重複を避けるために OneSignal からのみ送信してください。

急速に変化する更新に対して複数の通知を防ぐには?

通知作成 API で collapse_id を使用して、通知を積み重ねる代わりに以前の通知を置き換えます。複数の通知が同じ collapse_id を共有する場合、各新しい通知はトレイ内の前の通知を置き換えます。これは株価更新、ライブスコア、配送の到着予定時刻、および同様の頻繁な更新に役立ちます。

関連ページ

モバイル SDK トラブルシューティング

iOS および Android でのプッシュ通知配信に関する一般的な問題を解決します。

Web プッシュトラブルシューティング

Web プッシュのサブスクリプション、Service Worker、配信の問題をデバッグします。

アプリ内メッセージトラブルシューティング

アプリ内メッセージの表示、トリガー、重複に関する問題を修正します。

モバイルサービス拡張機能

iOS および Android で表示前にプッシュ通知を傍受してカスタマイズします。

通知が表示されない(Web)

送信されたが表示されない Web プッシュ通知のトラブルシューティング。