Android应用后台/被杀时无法从FCM通知中提取数据问题求解
FCM后台/进程被杀场景无法提取推送数据解决方案
这个问题本质是FCM的消息类型分发逻辑差异导致的,可按以下方案解决:
问题原因
FCM推送分为两类消息,不同场景下的分发逻辑不同:
- 通知类型消息:应用前台时走自定义
FirebaseMessagingService的onMessageReceived回调,可直接提取数据;应用后台/进程被杀时,通知由系统通知栏直接托管,点击默认打开启动页,自定义数据不会主动传入业务Activity - 数据类型消息:所有场景都走
onMessageReceived回调,可自主控制通知弹出和数据传递,完全不受前后台状态影响
解决方案
方案1:推送端统一使用数据类型消息(优先推荐)
推送payload不携带notification字段,仅传递data字段,所有场景都由应用自身控制通知弹出和数据传递:
// FirebaseMessagingService的onMessageReceived示例代码 @Override public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); // 提取自定义数据 Map<String, String> data = remoteMessage.getData(); // 构造跳转Intent,将数据塞入bundle Intent intent = new Intent(this, TargetActivity.class); for (Map.Entry<String, String> entry : data.entrySet()) { intent.putExtra(entry.getKey(), entry.getValue()); } PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // 自定义弹出通知 NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("fcm_push", "消息推送", NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } Notification notification = new NotificationCompat.Builder(this, "fcm_push") .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle(data.get("title")) .setContentText(data.get("content")) .setContentIntent(pendingIntent) .setAutoCancel(true) .build(); notificationManager.notify((int) System.currentTimeMillis(), notification); }
方案2:必须使用带notification的混合推送时适配启动页
如果推送端无法修改消息类型,点击通知后系统会把所有data字段内容塞入启动页的Intent extras中,在启动页中接收后再转发到业务页面即可:
// 启动页Activity示例代码 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); handlePushData(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handlePushData(intent); } private void handlePushData(Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { for (String key : extras.keySet()) { // 过滤FCM系统自带字段,仅提取自定义业务数据 if (!key.startsWith("google.") && !key.startsWith("gcm.")) { String value = extras.getString(key); // 拿到数据后自行处理跳转逻辑 } } } }
注意事项
- Android 12及以上创建
PendingIntent时必须显式指定FLAG_IMMUTABLE或FLAG_MUTABLE,否则数据会丢失 - 部分定制ROM会限制进程被杀后冷启动的Intent数据传递,优先选择方案1可完全规避系统托管逻辑
内容的提问来源于stack exchange,提问作者Code Learner.
相关产品推荐
相关产品推荐

