Logo Site EngageLab Mark Colored Transparent文档
搜索

如何兼容 FCM/APNs Token 直连推送

适用场景

如果您的 App 符合以下情况,本文适用于您:

  • App 已直接对接 Google FCM 和 iOS APNs,自身持有 FCM Token 与 APNs Token,按原生推送协议自主推送;
  • 历史版本 App 未集成 EngageLab AppPush SDK,大量存量用户没有 EngageLab 的 registration_id,无法通过 创建推送 API 触达;
  • 希望在不强制升级 App 的前提下,先把这些存量用户纳入 EngageLab 推送体系,再逐步迁移到 SDK。

方案概览

EngageLab 为这一场景提供 设备注册 API:服务端直接提交已持有的 FCM Token 或 APNs Device Token,EngageLab 为其生成唯一关联的 registration_id。之后即可像 SDK 注册用户一样,通过创建推送 API 按 registration_id 下发消息,并使用标签、别名、统计等基于 registration_id 的能力。

flowchart LR
    token["您已持有的<br/>FCM / APNs Token"]
    register["设备注册 API<br/>/v4/devices/token/registration_id"]
    regId["registration_id"]
    push["创建推送 API<br/>/v4/push"]
    device["用户设备收到通知"]

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

接入步骤:

  1. 服务端调用设备注册 API,按平台批量提交 Token(单次 1~500 个),保存返回的 registration_id 与 Token 的映射;
  2. 推送时在创建推送 API 的 to.registration_id 中填入目标用户的 registration_id
  3. Token 发生变化(FCM onNewToken、APNs 重新注册)时,重新调用设备注册 API 获取新的 registration_id

接入后一个常见问题是:用户在手机上点击通知后,App 会打开首页,还是能直接进入订单详情等目标页面?下文以 Android FCM 为例说明。

以下「通知点击跳转」部分仅覆盖 Android 原生 FCM 通知 场景。iOS(APNs Token 注册)的点击跳转不在本文讨论范围内。

通知点击跳转:结论

可以实现目标页跳转,但不是注册了 registration_id 之后就自动具备。

  • 默认情况下,点击通知只会打开 App;
  • 具体进入哪个页面,由您的 App 自身的点击处理逻辑决定;
  • 若要跳转到目标页,需要服务端在推送请求中指定 intent.url,并由您的 App 提供能够响应该 action 的 Activity。

设备注册 API 只负责建立 FCM Token 与 registration_id 的映射关系,不会给您的 App 增加任何页面跳转能力;这类用户也不会走依赖 EngageLab SDK 的通知点击中转逻辑。因此这是一种过渡期方案,长期仍建议迁移到 EngageLab AppPush SDK,详见文末「长期建议」章节。

默认行为:不配置点击动作

当推送请求中没有配置 notification.android.intent 时,EngageLab 下发给 FCM 的通知不携带 click_action。此时的点击表现完全遵循 FCM 的默认行为:

  • App 在后台或已被杀掉时,通知由 FCM 自动展示,点击后打开 App 的启动 Activity(即 AndroidManifest.xml 中声明为 MAIN/LAUNCHER 的 Activity);
  • 最终用户看到的是首页、登录页,还是恢复到之前停留的页面,取决于您的 App 的启动逻辑和当前任务栈状态。

因此「默认打开 App」并不等价于「一定回到首页」。详见 Firebase 官方说明:在 Android 应用中接收消息

实现目标页跳转:intent.url → click_action

映射链路

EngageLab 服务端会把创建推送 API 中 notification.android.intent.url 的值,映射为 FCM 通知的 android.notification.click_action 字段,再由 Android 系统在您的 App 中查找能够匹配该 action 的 Activity。

flowchart LR
    pushApi["创建推送 API<br/>notification.android.intent.url"]
    fcm["FCM 消息<br/>android.notification.click_action"]
    activity["您的 App<br/>匹配该 action 的 Activity"]
    target["业务目标页<br/>(如订单详情)"]

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

click_action 的官方定义见 FCM AndroidNotification

步骤一:服务端在推送请求中指定 intent.url

registration_id 推送时,在 notification.android 中增加 intent.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),不是随意填写的网页地址;
  • action 是您的 App 自定义的动作名称,component包名/Activity 全类名
  • 同一 urlactioncomponent 可以只填其一,但建议同时填写,以便精确命中目标 Activity;
  • 更多取值类型(打开首页、Deeplink 等)见创建推送 API 中 android 通知字段intent 说明。

步骤二:您的 App 提供匹配的 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)
    }
}

            
此代码块在浮窗中显示

若您的 App 已经有统一的路由中转页(例如所有通知点击都先进入 PushRouterActivity,再根据参数分发到具体页面),可以把 intent.urlcomponent 指向该中转页,由中转页读取 extras 后再跳转到订单详情等业务页面,无需为每个业务页面单独声明 action。

注意事项

  • 是否需要集成 EngageLab SDK: 不需要。上述链路只依赖 FCM 的 click_action 机制和您的 App 自身的 Activity 声明。
  • 已有 click_action 处理可复用: 如果您的 App 之前直接使用 FCM 推送时已经实现了 click_action 处理逻辑,只需把原来的 action 值填入 intent.url 即可复用。
  • 没有 click_action 处理需要补充: 若您的 App 目前只依赖默认打开行为,需要按「步骤二」增加 Activity 声明和参数解析逻辑,否则即使服务端配置了 intent.url,系统也找不到可响应的 Activity。
  • 业务参数通过 extras 传递: intent.url 用于决定「打开哪个页面」,页面内展示什么内容建议通过 extras 传递(如 order_id),由目标 Activity 自行解析。
  • App 在前台时的表现: App 在前台时,FCM 不会自动展示通知,而是回调到您的 App 的 onMessageReceived,是否展示通知以及点击后如何跳转均由您的 App 自行实现。
  • 验证方法: 联调时可先用 intent:#Intent;action=android.intent.action.MAIN;end 确认通道链路正常,再替换为业务 action 验证目标页跳转。

长期建议:尽快迁移到 EngageLab AppPush SDK

设备注册 API 定位于兼容过渡方案,用于让历史版本 App 的存量用户在未集成 SDK 的情况下也能被触达,并生成关联的 registration_id,为后续接入 EngageLab AppPush 的其他能力做准备。它解决的是「能不能推到」的问题,而不是替代 SDK。

我们建议您把它作为迁移策略的一部分,而不是长期方案:

  • 新版本 App 集成 EngageLab AppPush SDK: 新用户通过 SDK 标准注册获得 registration_id,直接享有完整的通知展示与点击处理能力。
  • 旧版本 App 用直连 Token 过渡: 存量用户通过设备注册 API 注册的 registration_id 继续推送,两套体系可以共存,不需要强制合并。
  • 随版本更新逐步收敛: 随着用户升级到集成 SDK 的版本,直连 Token 用户会自然减少,最终统一到 SDK 体系。

相比本文介绍的直连方式,集成 SDK 后:

  • 通知点击跳转由 SDK 统一处理,intent.url 支持的三种类型(指定 Activity、应用首页、Deeplink)无需您在 App 侧逐个声明 action 与解析逻辑;
  • 前台通知展示、通知栏样式(builder_idstylechannel_id 等)、角标、消息折叠等字段才能完整生效;
  • SDK 会自动上报设备信息与点击等行为,控制台的送达、点击统计更完整。

集成方式请参考 Android SDK 集成指南iOS SDK 集成指南

Icon Solid Transparent White Qiyu
联系销售