Android后台FCM通知样式异常、无法跳转及无回调问题求助
问题描述
App处于前台时,自定义FCM通知功能正常:通过FirebaseMessageReceiver(继承FirebaseMessagingService)生成的自定义通知可正常展示,点击能跳转至指定的SplashScreenActivity1。但App处于后台时,出现以下问题:
- 通知样式不符合代码中定义的自定义样式(如颜色异常);
- 点击通知无法打开目标Activity;
FirebaseMessageReceiver的onMessageReceived方法无回调。
相关代码
FirebaseMessageReceiver类
public class FirebaseMessageReceiver extends FirebaseMessagingService { public static final String FCM_PARAM = "picture"; private static final String CHANNEL_NAME = "FCM"; private static final String CHANNEL_DESC = "Firebase Cloud Messaging"; private int numMessages = 0; Bitmap bitmap; @Inject AppPreference appPreference; @Override public void onMessageReceived(RemoteMessage remoteMessage) { AndroidInjection.inject(this); super.onMessageReceived(remoteMessage); RemoteMessage.Notification notification = remoteMessage.getNotification(); Map<String, String> data = remoteMessage.getData(); Log.d("FromNotification", remoteMessage.getFrom()); sendNotificaionBroadcast(); if (remoteMessage.getNotification().getImageUrl() != null) { String imageUri = remoteMessage.getNotification().getImageUrl().toString(); bitmap = getBitmapFromUrl(imageUri); sendNotification(notification, data, bitmap); } else { sendNotification(notification, data, null); } } private void sendNotification(RemoteMessage.Notification notification, Map<String, String> data, Bitmap bitmap) { Bundle bundle = new Bundle(); bundle.putString(FCM_PARAM, data.get(FCM_PARAM)); appPreference.setNewNotification(true); Intent intent = new Intent(this, SplashScreenActivity1.class); intent.putExtras(bundle); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id)) .setContentTitle(notification.getTitle()) .setContentText(notification.getBody()) .setAutoCancel(true) .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) //.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.win)) .setContentIntent(pendingIntent) .setContentInfo("RoveDashCam") .setLargeIcon(bitmap) .setColor(Color.parseColor("#80FF8C00")) .setLights(Color.RED, 1000, 300) .setDefaults(Notification.DEFAULT_VIBRATE) .setNumber(++numMessages) .setSmallIcon(R.drawable.ic_notification); try { String picture = data.get(FCM_PARAM); if (picture != null && !"".equals(picture)) { URL url = new URL(picture); Bitmap bigPicture = BitmapFactory.decodeStream(url.openConnection().getInputStream()); notificationBuilder.setStyle( new NotificationCompat.BigPictureStyle().bigPicture(bigPicture).setSummaryText(notification.getBody()) ); } } catch (IOException e) { e.printStackTrace(); } NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( getString(R.string.notification_channel_id), CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT ); channel.setDescription(CHANNEL_DESC); channel.setShowBadge(true); channel.canShowBadge(); channel.enableLights(true); channel.setLightColor(Color.RED); channel.enableVibration(true); channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500}); assert notificationManager != null; notificationManager.createNotificationChannel(channel); } assert notificationManager != null; notificationManager.notify(0, notificationBuilder.build()); } public Bitmap getBitmapFromUrl(String imageUrl) { try { URL url = new URL(imageUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.connect(); InputStream input = connection.getInputStream(); return BitmapFactory.decodeStream(input); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } private void sendNotificaionBroadcast() { Intent intent = new Intent("IntentFilterAction"); intent.putExtra("MyDataKey", "myData"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } }
AndroidManifest配置
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/notification_channel_id" /> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_notification" /> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/white" /> <service android:name="com.rovedashcam.newmodeule.base.commondots.FirebaseMessageReceiver" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
问题分析与解决方案
问题3:onMessageReceived后台无回调
原因:FCM分通知消息和数据消息两类。App后台时,带notification字段的通知消息会被系统直接处理,不会触发onMessageReceived;只有纯data字段的数据消息才会在后台调用该方法。
修改方案:
- 调整消息发送格式:只传
data字段,去掉notification字段,让消息以数据消息形式传递,确保后台也能触发onMessageReceived。
问题1:后台通知样式不符合自定义样式
原因:后台收到带notification字段的消息时,系统会用Manifest中配置的默认参数生成通知,不会执行代码里的自定义样式逻辑。
修改方案:
- 采用纯数据消息格式,让
onMessageReceived在后台执行,从而调用你写的sendNotification方法应用自定义样式。 - 若无法改消息格式,调整Manifest的默认配置:比如把
default_notification_color改成你需要的颜色(先在colors.xml定义<color name="custom_notification_color">#80FF8C00</color>,再修改meta-data为android:resource="@color/custom_notification_color")。
问题2:点击通知无法打开目标Activity
原因:
- 系统展示默认通知时,点击行为由
notification字段的click_action控制,未设置则打开主Activity,而非指定页面。 - 用PendingIntent时,后台场景下Intent缺少必要启动标志,导致Activity无法正确启动。
修改方案:
- 若用纯数据消息:给Intent添加启动标志,确保后台能启动目标Activity:
Intent intent = new Intent(this, SplashScreenActivity1.class); intent.putExtras(bundle); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); // 添加该行 PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
- 若必须保留
notification字段:发送消息时添加click_action参数,值为Manifest中给SplashScreenActivity1配置的action名称,同时在Manifest中添加对应intent-filter:
<activity android:name=".SplashScreenActivity1"> <intent-filter> <action android:name="YOUR_CUSTOM_CLICK_ACTION" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
额外优化
- 通知Channel创建逻辑:当前每次收消息都创建Channel,冗余且无意义,建议移到Application的
onCreate方法中初始化,仅创建一次。 - PendingIntent的requestCode:当前用0,多通知会导致PendingIntent被覆盖,建议用唯一值(比如时间戳、消息ID)。
内容的提问来源于stack exchange,提问作者MARSH
相关产品推荐
相关产品推荐

