FCM/APNs トークンによる直接プッシュへの対応方法

適用シナリオ

お客様のアプリが以下の状況に該当する場合、本記事が役立ちます。

  • アプリがすでに Google FCM と iOS APNs に直接接続しており、FCM トークンと APNs トークンを自社で保持し、ネイティブのプッシュプロトコルで自主的に配信している。
  • 過去バージョンのアプリに EngageLab AppPush SDK が組み込まれておらず、多数の既存ユーザーが EngageLab の registration_id を持たないため、プッシュ作成 API で到達できない。
  • アプリの強制アップデートを行わずに、まずこれらの既存ユーザーを EngageLab のプッシュ体系に取り込み、その後段階的に SDK へ移行したい。

ソリューション概要

EngageLab はこのシナリオ向けに デバイス登録 API を提供しています。サーバー側から保持している FCM トークンまたは APNs デバイストークンを直接送信すると、EngageLab がそれぞれに一意に関連付けられた registration_id を生成します。以降は SDK 登録ユーザーと同様に、プッシュ作成 API で registration_id を指定してメッセージを配信でき、タグ・エイリアス・統計など registration_id に基づく機能も利用できます。

flowchart LR
    token["お客様が保持する<br/>FCM / APNs トークン"]
    register["デバイス登録 API<br/>/v4/devices/token/registration_id"]
    regId["registration_id"]
    push["プッシュ作成 API<br/>/v4/push"]
    device["ユーザーのデバイスが通知を受信"]

    token --> register --> regId --> push --> device

導入手順:

  1. サーバー側でデバイス登録 API を呼び出し、プラットフォームごとにトークンを一括送信(1 回あたり 1~500 件)し、返却された registration_id とトークンの対応関係を保存します。
  2. 配信時に、プッシュ作成 API の to.registration_id に対象ユーザーの registration_id を指定します。
  3. トークンが変化した場合(FCM の onNewToken、APNs の再登録)は、デバイス登録 API を再度呼び出して新しい registration_id を取得します。

導入後によくある質問として、「ユーザーが端末で通知をタップした後、アプリはホーム画面を開くのか、それとも注文詳細などの目的画面に直接遷移できるのか」があります。以下では Android FCM を例に説明します。

以下の「通知タップ時の遷移」に関する部分は Android ネイティブ FCM 通知 のシナリオのみを対象としています。iOS(APNs トークン登録)のタップ時遷移は本記事の対象外です。

通知タップ時の遷移:結論

目的画面への遷移は実現できますが、registration_id を登録しただけで自動的に備わるものではありません。

  • デフォルトでは、通知をタップするとアプリが開くだけです。
  • どの画面に遷移するかは、お客様のアプリ自身のタップ処理ロジックによって決まります。
  • 目的画面に遷移させるには、サーバー側がプッシュリクエストで intent.url を指定し、かつお客様のアプリ側でその action に応答できる Activity を用意する必要があります。

デバイス登録 API は FCM トークンと registration_id の対応関係を確立するだけで、お客様のアプリに画面遷移機能を追加することはありません。また、これらのユーザーは EngageLab SDK に依存する通知タップの中継ロジックを経由しません。したがってこれは過渡期の方式であり、長期的には EngageLab AppPush SDK への移行を推奨します。詳細は末尾の「長期的な推奨事項」をご覧ください。

デフォルト動作:タップ動作を設定しない場合

プッシュリクエストに notification.android.intent が設定されていない場合、EngageLab が FCM に送る通知には click_action が含まれません。このときのタップ動作は FCM のデフォルト動作に完全に従います。

  • アプリがバックグラウンドまたは終了している場合、通知は FCM によって自動表示され、タップするとアプリの起動 Activity(AndroidManifest.xmlMAIN/LAUNCHER として宣言された Activity)が開きます。
  • エンドユーザーに表示されるのがホーム画面か、ログイン画面か、以前に開いていた画面かは、お客様のアプリの起動ロジックと現在のタスクスタックの状態によって決まります。

そのため、「デフォルトでアプリが開く」は「必ずホーム画面に戻る」と同義ではありません。詳しくは Firebase 公式ドキュメント Android アプリでメッセージを受信する をご参照ください。

目的画面への遷移の実現:intent.url → click_action

マッピングの流れ

EngageLab サーバーは、プッシュ作成 API の notification.android.intent.url の値を FCM 通知の android.notification.click_action フィールドにマッピングします。その後、Android システムがお客様のアプリ内でその action に一致する Activity を探します。

flowchart LR
    pushApi["プッシュ作成 API<br/>notification.android.intent.url"]
    fcm["FCM メッセージ<br/>android.notification.click_action"]
    activity["お客様のアプリ<br/>action に一致する Activity"]
    target["業務上の目的画面<br/>(注文詳細など)"]

    pushApi --> fcm --> activity --> target

click_action の公式定義は FCM AndroidNotification をご参照ください。

ステップ 1:サーバー側でプッシュリクエストに intent.url を指定する

registration_id 宛てに配信する際、notification.androidintent.url を追加し、業務パラメータは extras で渡します。

curl -X POST https://pushapi-sgp.engagelab.com/v4/push \ -u "appKey:masterSecret" \ -H "Content-Type: application/json" \ -d '{ "from": "push", "to": { "registration_id": ["13065ffa4e1a6cc91c3"] }, "body": { "platform": "android", "notification": { "android": { "title": "ご注文を発送しました", "alert": "ご注文 20260911001 を発送しました。タップして配送状況を確認", "intent": { "url": "intent:#Intent;action=com.example.app.ORDER_DETAIL;component=com.example.app/com.example.app.OrderDetailActivity;end" }, "extras": { "order_id": "20260911001", "page": "order_detail" } } } }, "request_id": "order-shipped-20260911001" }'
              
              curl -X POST https://pushapi-sgp.engagelab.com/v4/push \
  -u "appKey:masterSecret" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "push",
    "to": {
      "registration_id": ["13065ffa4e1a6cc91c3"]
    },
    "body": {
      "platform": "android",
      "notification": {
        "android": {
          "title": "ご注文を発送しました",
          "alert": "ご注文 20260911001 を発送しました。タップして配送状況を確認",
          "intent": {
            "url": "intent:#Intent;action=com.example.app.ORDER_DETAIL;component=com.example.app/com.example.app.OrderDetailActivity;end"
          },
          "extras": {
            "order_id": "20260911001",
            "page": "order_detail"
          }
        }
      }
    },
    "request_id": "order-shipped-20260911001"
  }'

            
このコードブロックはフローティングウィンドウ内に表示されます

intent.url の値については以下の点に注意してください。

  • Android の Intent URI 形式(intent:#Intent;...;end)であり、任意の Web ページ URL ではありません。
  • action はお客様のアプリで定義した独自のアクション名、componentパッケージ名/Activity の完全クラス名 です。
  • 同一の url 内で actioncomponent はどちらか一方のみでも指定できますが、目的の Activity を正確に特定するため両方を指定することを推奨します。
  • その他の指定方法(ホーム画面を開く、Deeplink など)は、プッシュ作成 API の android 通知フィールド にある intent の説明をご参照ください。

ステップ 2:お客様のアプリで一致する Activity を用意する

AndroidManifest.xml で、目的の Activity に intent.urlaction と一致する intent-filter を宣言します。

<activity android:name=".OrderDetailActivity" android:exported="true"> <intent-filter> <action android:name="com.example.app.ORDER_DETAIL" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
              
              <activity
    android:name=".OrderDetailActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.app.ORDER_DETAIL" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

            
このコードブロックはフローティングウィンドウ内に表示されます

FCM が通知を表示し、それがタップされると、その action で対応する Activity が起動され、通知の extras のキーと値が Intent の extras に格納されます。目的の Activity でパラメータを読み取り、業務上のルーティングを行います。

class OrderDetailActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val orderId = intent.getStringExtra("order_id") if (orderId.isNullOrEmpty()) { // パラメータがない場合は注文一覧またはホーム画面にフォールバック startActivity(Intent(this, MainActivity::class.java)) finish() return } showOrderDetail(orderId) } }
              
              class OrderDetailActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val orderId = intent.getStringExtra("order_id")
        if (orderId.isNullOrEmpty()) {
            // パラメータがない場合は注文一覧またはホーム画面にフォールバック
            startActivity(Intent(this, MainActivity::class.java))
            finish()
            return
        }
        showOrderDetail(orderId)
    }
}

            
このコードブロックはフローティングウィンドウ内に表示されます

お客様のアプリにすでに統一されたルーティング用の中継画面がある場合(例:すべての通知タップをまず PushRouterActivity に入れ、パラメータに応じて各画面に振り分ける)、intent.urlcomponent をその中継画面に向けることができます。中継画面が extras を読み取ってから注文詳細などの業務画面に遷移するため、業務画面ごとに個別の action を宣言する必要はありません。

注意事項

  • EngageLab SDK の組み込みは必要か: 不要です。上記の流れは FCM の click_action の仕組みと、お客様のアプリ自身の Activity 宣言のみに依存します。
  • 既存の click_action 処理は再利用可能: お客様のアプリが以前 FCM を直接利用していた際に click_action の処理ロジックを実装済みであれば、元の action 値を intent.url に指定するだけで再利用できます。
  • click_action 処理がない場合は追加が必要: お客様のアプリが現在デフォルトの起動動作のみに依存している場合、「ステップ 2」に従って Activity の宣言とパラメータ解析ロジックを追加する必要があります。そうしないと、サーバー側で intent.url を設定しても、システムは応答できる Activity を見つけられません。
  • 業務パラメータは extras で渡す: intent.url は「どの画面を開くか」を決めるためのものです。画面内に表示する内容は extrasorder_id など)で渡し、目的の Activity 側で解析することを推奨します。
  • アプリがフォアグラウンドにあるときの動作: アプリがフォアグラウンドにある場合、FCM は通知を自動表示せず、お客様のアプリの onMessageReceived にコールバックします。通知を表示するか、タップ後にどう遷移するかは、すべてお客様のアプリ側で実装します。
  • 検証方法: 結合テスト時は、まず intent:#Intent;action=android.intent.action.MAIN;end でチャネルの経路が正常であることを確認し、その後業務用の action に置き換えて目的画面への遷移を検証します。

長期的な推奨事項:できるだけ早く EngageLab AppPush SDK へ移行する

デバイス登録 API は 互換性のための過渡的なソリューション と位置付けられています。過去バージョンのアプリの既存ユーザーに対し、SDK を組み込まなくても到達できるようにし、関連付けられた registration_id を生成して、今後 EngageLab AppPush の他の機能を利用するための準備を整えるものです。解決するのは「届けられるかどうか」の問題であり、SDK の代替ではありません。

これは長期的な方式ではなく、移行戦略の一部として位置付けることを推奨します。

  • 新バージョンのアプリは EngageLab AppPush SDK を組み込む: 新規ユーザーは SDK の標準登録で registration_id を取得し、完全な通知表示とタップ処理機能をそのまま利用できます。
  • 旧バージョンのアプリは直接トークンで移行期間を乗り切る: 既存ユーザーはデバイス登録 API で登録した registration_id で引き続き配信を受けます。両方の体系は共存でき、強制的に統合する必要はありません。
  • バージョン更新に伴って段階的に収束させる: ユーザーが SDK 組み込み版にアップデートするにつれ、直接トークンのユーザーは自然に減少し、最終的に SDK 体系に統一されます。

本記事で紹介した直接接続方式と比べ、SDK を組み込むと次の利点があります。

  • 通知タップ時の遷移は SDK が統一的に処理し、intent.url がサポートする 3 種類(特定の Activity、アプリのホーム画面、Deeplink)について、アプリ側で action の宣言や解析ロジックを個別に用意する必要がありません。
  • フォアグラウンドでの通知表示、通知スタイル(builder_idstylechannel_id など)、バッジ、メッセージの折りたたみなどのフィールドが完全に機能します。
  • SDK がデバイス情報やタップなどの行動を自動的にレポートするため、コンソールの到達・タップ統計がより完全になります。

組み込み方法は Android SDK 統合ガイドiOS SDK 統合ガイド をご参照ください。

Icon Solid Transparent White Qiyu
お問い合わせ