如何区分应用从无数据FCM通知与应用图标启动的场景?
区分FCM通知启动与应用图标启动的方案
这个问题我做FCM集成时也碰到过,确实因为通知不带数据,导致常规的extras判断失效,不过有两个比较靠谱的解决思路:
方法一:利用FCM的click_action字段(推荐)
这是最直接的方案,只需要后端在推送通知时添加click_action参数,就能让系统在用户点击通知时,给启动Intent带上自定义的Action,以此区分图标启动的场景。
步骤1:后端修改推送Payload
在FCM的通知Payload里加入click_action,指定一个自定义的Action名称,比如OPEN_NOTIFICATION_SECTION:
{ "notification": { "title": "你的通知标题", "click_action": "OPEN_NOTIFICATION_SECTION" }, "to": "目标设备的FCM令牌" }
步骤2:配置AndroidManifest.xml
给你的主Activity添加对应的<intent-filter>,让它能响应这个自定义Action:
<activity android:name=".MainActivity" android:exported="true"> <!-- 原有图标启动的intent-filter --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- 新增处理通知点击的intent-filter --> <intent-filter> <action android:name="OPEN_NOTIFICATION_SECTION" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
步骤3:在Activity中判断启动来源
在MainActivity的onCreate和onNewIntent(如果是singleTop等启动模式)里,通过Intent的Action来区分:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) handleLaunchIntent(intent) } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) setIntent(intent) handleLaunchIntent(intent) } private fun handleLaunchIntent(intent: Intent?) { intent?.let { when (it.action) { "OPEN_NOTIFICATION_SECTION" -> { // 来自通知点击,跳转到通知板块 navigateToNotificationSection() } "android.intent.action.MAIN" -> { // 来自应用图标点击,正常初始化 } } } } private fun navigateToNotificationSection() { // 这里写跳转到通知板块的逻辑,比如Fragment跳转或Activity跳转 supportFragmentManager.beginTransaction() .replace(R.id.container, NotificationFragment()) .commit() }
方法二:自定义通知构建(适用于无法修改后端Payload的场景)
如果后端没办法调整推送内容,你可以在客户端拦截FCM通知,自己构建带有标识的PendingIntent,替换系统默认的通知行为。
步骤1:实现FirebaseMessagingService
创建自定义的FirebaseMessagingService,在onMessageReceived中自己构建通知,并给PendingIntent添加自定义标识:
class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) remoteMessage.notification?.let { fcmNotification -> // 构建启动Intent,添加自定义标识 val launchIntent = packageManager.getLaunchIntentForPackage(packageName)?.apply { putExtra("FROM_FCM_NOTIFICATION", true) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } ?: return val pendingIntent = PendingIntent.getActivity( this, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // 构建自定义通知 val notificationBuilder = NotificationCompat.Builder(this, "NOTIFICATION_CHANNEL_ID") .setSmallIcon(R.drawable.ic_notification) .setContentTitle(fcmNotification.title ?: "") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .setAutoCancel(true) // 确保通知渠道存在(Android 8.0+要求) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "NOTIFICATION_CHANNEL_ID", "通知频道", NotificationManager.IMPORTANCE_DEFAULT ) notificationManager.createNotificationChannel(channel) } // 显示自定义通知 notificationManager.notify(System.currentTimeMillis().toInt(), notificationBuilder.build()) } } }
步骤2:在Activity中判断标识
和方法一类似,在MainActivity中读取Intent的自定义参数:
private fun handleLaunchIntent(intent: Intent?) { intent?.let { val fromNotification = it.getBooleanExtra("FROM_FCM_NOTIFICATION", false) if (fromNotification) { navigateToNotificationSection() } } }
注意:这个方法的前提是,应用在后台时FCM会将通知消息传递到
onMessageReceived。但根据FCM规则,当应用完全未运行时,纯通知消息会由系统直接展示,不会进入onMessageReceived,所以这种情况下方法一的兼容性更好。
内容的提问来源于stack exchange,提问作者Lucas P.
相关产品推荐
相关产品推荐

