You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

原因:

  1. 系统展示默认通知时,点击行为由notification字段的click_action控制,未设置则打开主Activity,而非指定页面。
  2. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 17:37:00