FCM集成问题:后台/进程杀死时onMessageReceived未触发及前台推送空白
分析与解决方案
咱们逐个拆解你遇到的核心问题:后台/进程杀死时onMessageReceived不触发、前台推送通知空白、点击通知直接启动启动页,这些问题大多和FCM的payload处理规则、代码里的空指针异常(NPE)以及系统通知逻辑有关。
1. 前台推送空白+onMessageReceived异常崩溃
你的代码里有个致命的NPE问题!因为后端发送的是纯data payload,没有notification字段,所以remoteMessage.getNotification()会返回null,这行代码直接导致onMessageReceived方法崩溃,后续的通知创建逻辑完全没执行:
// 这行代码会抛出NPE,必须移除! Log.e("remote message >>", remoteMessage.getNotification().getBody() + "");
修复方案:
直接删除这行调用remoteMessage.getNotification()的代码,确保onMessageReceived能正常执行到handleDataMessage方法,进而创建本地通知。
2. 后台/进程杀死时onMessageReceived不调用+点击通知进启动页
FCM对纯data payload的处理规则是:
- 应用前台:
onMessageReceived会被正常调用,由你自己处理消息和创建通知。 - 应用后台/进程杀死:系统会自动接收消息,并将data字段的参数附加到启动Activity的Intent中,此时
onMessageReceived不会被调用(这是FCM的默认行为)。
你看到点击通知直接进启动页,是因为系统默认把启动页(Launcher Activity)作为通知的跳转目标,而你没有在启动页里处理这些附加的参数。
修复方案:
在你的启动页(比如SplashActivity,或者被设置为Launcher的Activity)的onCreate方法中,读取Intent里的extras,处理FCM传递的data参数:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); // 处理FCM传递的data payload参数 Intent incomingIntent = getIntent(); if (incomingIntent != null && incomingIntent.getExtras() != null) { Bundle extras = incomingIntent.getExtras(); // 注意key要和后端发送的一致:"job_id"、"stage" int jobId = extras.getInt("job_id", 0); String stage = extras.getString("stage", ""); if (jobId > 0 && !stage.isEmpty()) { // 跳转到目标页面并传递参数 Intent homeIntent = new Intent(this, VendorHomeActivity.class); homeIntent.putExtra("jobId", jobId); homeIntent.putExtra("stage", stage); homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(homeIntent); finish(); // 结束启动页 } } }
3. 通知渠道的合法性问题
你的代码里创建通知时用了空字符串作为channelId,在Android 8.0(API 26)及以上版本,这会导致通知无法正常显示:
String channelId = ""; // 空渠道ID不合法
修复方案:
创建一个合法的通知渠道ID,确保渠道创建逻辑正确:
// 修改localNotification方法中的渠道相关代码 String channelId = "fyxt_notification_channel"; // 自定义渠道ID Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.fyxt_logo) .setContentTitle(title) .setContentText(message) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(resultPendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建通知渠道 NotificationChannel channel = new NotificationChannel( channelId, "FYXT 通知", // 渠道名称(用户可见) NotificationManager.IMPORTANCE_DEFAULT ); channel.setDescription("应用推送通知渠道"); // 渠道描述(用户可见) notificationManager.createNotificationChannel(channel); }
4. 额外的细节优化
- BroadcastReceiver的生命周期管理:确保你的Activity在
onResume时注册广播接收器,onPause时注销,避免内存泄漏:@Override protected void onResume() { super.onResume(); LocalBroadcastManager.getInstance(this).registerReceiver( notificationReceiver, new IntentFilter(Constants.PUSH_NOTIFICATION_INTENT) ); } @Override protected void onPause() { super.onPause(); LocalBroadcastManager.getInstance(this).unregisterReceiver(notificationReceiver); } - PendingIntent的Flags:如果需要确保每次点击通知都能传递最新的参数,可以使用
PendingIntent.FLAG_UPDATE_CURRENT替代FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT。
内容的提问来源于stack exchange,提问作者Manikandan
相关产品推荐
相关产品推荐

