从通知冷启动Android应用时如何获取Intent Extras?
应用冷启动时点击通知无法获取Intent Extras的解决方法
问题描述
当应用未运行或不在后台时,点击通知启动应用无法获取Intent中的extras;但应用处于运行或后台状态时,可正常获取这些extras。当前SplashActivity为应用的主活动,需解决冷启动时获取extras的问题。
问题重现
冷启动时SplashActivity的日志显示:
onCreate: intent action android.intent.action.MAIN
onCreate: intent test extra -1 // 预期值为16
相关代码
PushNotificationService代码
val intent = Intent(this, SplashActivity::class.java).apply { flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK putExtra("TEST", 16) } val pendingIntent = PendingIntent.getActivity(this, Random.nextInt(), intent, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)
AndroidManifest配置
<application android:name=".HiltApplication" android:allowBackup="true" android:icon="@mipmap/app_logo" android:label="@string/app_name" android:roundIcon="@mipmap/app_logo_round" android:supportsRtl="true" android:theme="@style/Theme.X"> <activity android:name=".SplashActivity" android:exported="true" android:screenOrientation="portrait" android:theme="@style/Theme.X.Splash"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".service.PushNotificationService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/notification_channel_general" /> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@mipmap/app_logo" /> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/blue" /> </application>
SplashActivity代码
@AndroidEntryPoint class SplashActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Splash() } Log.d("SPLASH", "onCreate: intent action ${intent.action}") Log.d("SPLASH", "onCreate: intent test extra ${intent.getIntExtra("TEST", -1)}") } }
FCM通知Payload
const message = { token: "TOKEN", notification: { title: d.title, body: d.content }, android: { notification: { channel_id: "fcm_channel", }, }, data: { title: d.title, content: d.content, }, };
问题原因
当FCM消息包含notification字段时,若应用处于后台或未运行状态,系统会自动接管通知展示,此时点击通知会直接启动应用的Launcher Activity(SplashActivity),并不会使用你在PushNotificationService中创建的自定义PendingIntent,导致手动添加的TEST extra无法被传递。
解决方案
方案一:手动构建并展示通知(推荐)
在onMessageReceived中手动创建并展示通知,完全控制通知的点击行为,确保自定义extras能被传递:
override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 构建跳转Intent,携带自定义参数和FCM data数据 val intent = Intent(this, SplashActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP putExtra("TEST", 16) // 遍历FCM data字段,添加到Intent中 remoteMessage.data.forEach { (key, value) -> putExtra(key, value) } } // 创建唯一的PendingIntent,避免被覆盖 val pendingIntent = PendingIntent.getActivity( this, System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) // 构建通知 val notificationBuilder = NotificationCompat.Builder(this, getString(R.string.notification_channel_general)) .setSmallIcon(R.mipmap.app_logo) .setColor(ContextCompat.getColor(this, R.color.blue)) .setContentTitle(remoteMessage.notification?.title ?: "") .setContentText(remoteMessage.notification?.body ?: "") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .setAutoCancel(true) // 展示通知 val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(System.currentTimeMillis().toInt(), notificationBuilder.build()) }
方案二:调整Intent Flags并完善Activity逻辑
- 修改PendingIntent的Flags,避免使用
FLAG_ACTIVITY_CLEAR_TASK,改用可保留extras的组合:
val intent = Intent(this, SplashActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP putExtra("TEST", 16) }
- 在SplashActivity中重写
onNewIntent,统一处理Intent extras:
@AndroidEntryPoint class SplashActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Splash() } handleIntentExtras(intent) } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) setIntent(intent) // 更新当前Intent为最新的跳转Intent handleIntentExtras(intent) } private fun handleIntentExtras(intent: Intent?) { intent?.let { Log.d("SPLASH", "intent action ${it.action}") val testExtra = it.getIntExtra("TEST", -1) Log.d("SPLASH", "intent test extra $testExtra") // 处理FCM data中的内容 val title = it.getStringExtra("title") val content = it.getStringExtra("content") Log.d("SPLASH", "FCM data title: $title, content: $content") } } }
方案三:仅发送Data类型消息
在FCM消息Payload中移除notification字段,只保留data字段,这样所有消息都会被传递到onMessageReceived方法,无论应用状态如何,你可以完全自定义通知行为:
const message = { token: "TOKEN", data: { title: d.title, content: d.content, "TEST": "16" // Data字段的值必须为字符串类型 }, android: { notification: { channel_id: "fcm_channel", }, }, };
内容的提问来源于stack exchange,提问作者apphitect
相关产品推荐
相关产品推荐

