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

Android设备FCM推送场景差异分析及按应用状态控通知显示问询

FCM Notification Behavior Explanation & Custom Display Control

Hey there! Let's break down why you're seeing different notification behavior across your two Android devices, then walk through a solid solution to control notifications based on your app's state.

Why the Three Scenarios Behave Differently

First, let's recall how Firebase Cloud Messaging handles Notification Messages (the type you're sending from the Firebase Console):

Scenario 1 & 2: App Not Launched / In Background

When your app is closed or running in the background, FCM delivers the notification message directly to the Android system's notification service—not your MyFirebaseService. The system automatically displays the notification in the status bar, regardless of Android version (7.0 or 8.1). For Android 8.0+, the system uses a default notification channel to show the notification, which is why it works even though you didn't create one in your code.

Scenario 3: App In Foreground

When your app is active in the foreground, FCM sends the notification message to your onMessageReceived method instead of the system. Here's where the Android version difference kicks in:

  • Android 7.0 (API 24): No notification channel requirement, so your code successfully builds and shows the notification via notificationManager.notify().
  • Android 8.1 (API 27): Google introduced mandatory notification channels. Your code tries to build a notification with "channel_id", but you never created this channel in your app. Without a valid channel, the system rejects the notification request, so nothing shows up in the status bar.

Solution: Control Notifications Based on App State

To fix the version discrepancy and gain full control over when notifications are shown, follow these steps:

1. Add Foreground State Detection (Reliable Method)

Use Android's ProcessLifecycleOwner to track when your app moves to the foreground/background. This is more accurate than relying on ActivityManager.

First, add the lifecycle dependency to your build.gradle (Module level):

implementation "androidx.lifecycle:lifecycle-process:2.6.2"

Then create a custom Application class to track state and create the required notification channel:

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;
import android.app.Application;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;

public class MyApp extends Application implements LifecycleObserver {
    private static boolean isAppInForeground = false;

    @Override
    public void onCreate() {
        super.onCreate();
        // Register lifecycle observer to track app state
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
        // Create notification channel for Android 8+
        createNotificationChannel();
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onEnterForeground() {
        isAppInForeground = true;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onEnterBackground() {
        isAppInForeground = false;
    }

    public static boolean isAppForeground() {
        return isAppInForeground;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = "channel_id";
            String channelName = "Default Notifications";
            String channelDesc = "Channel for general app notifications";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;

            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
            channel.setDescription(channelDesc);

            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
}

Don't forget to register this Application class in your AndroidManifest.xml:

<application
    android:name=".MyApp"
    <!-- other attributes -->
>
    <!-- activities, services, etc. -->
</application>

2. Modify MyFirebaseService to Control Notifications

Update your onMessageReceived method to check the app's state and decide whether to show a notification. For full control, we recommend using Data Messages (instead of Notification Messages) from the Firebase Console—this ensures the message always reaches onMessageReceived, regardless of app state.

import android.content.Context;
import android.app.NotificationManager;
import android.media.RingtoneManager;
import android.net.Uri;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyFirebaseService extends FirebaseMessagingService {

    @Override
    public void onNewToken(String s) {
        // Keep your existing token logic here
        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(task -> {
                    if (!task.isSuccessful()) {
                        Log.w("getInstanceId failed", task.getException());
                        return;
                    }
                    String token = task.getResult().getToken();
                    Log.e("My Token", token);
                });
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        Log.d("push recibida", "push recibida " + remoteMessage);

        boolean isForeground = MyApp.isAppForeground();

        // Define your logic based on app state
        if (!isForeground) {
            // App is in background or closed: show notification
            showNotification(remoteMessage);
        } else {
            // App is in foreground: skip notification (or show a custom in-app alert)
            Log.d("Foreground State", "App is active, not showing status bar notification");
            // Optional: Show an in-app dialog or toast instead
            // showInAppAlert(remoteMessage);
        }
    }

    private void showNotification(RemoteMessage remoteMessage) {
        // For Data Messages: retrieve data from remoteMessage.getData()
        // For Notification Messages: use remoteMessage.getNotification() (but Data Messages are better for control)
        String title = remoteMessage.getData().getOrDefault("title", "Default Title");
        String body = remoteMessage.getData().getOrDefault("body", "Default Body");

        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "channel_id")
                .setContentTitle(title)
                .setContentText(body)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setStyle(new NotificationCompat.BigTextStyle())
                .setSound(defaultSoundUri)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setAutoCancel(true);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify((int) System.currentTimeMillis(), notificationBuilder.build());
        // Use a unique ID for each notification instead of 0 to avoid overwriting
    }
}

3. Send Data Messages from Firebase Console

When sending from the Firebase Console, switch to the Cloud Messaging tab, expand "Advanced options", and select "Data" instead of "Notification". Add key-value pairs like title and body—this ensures your onMessageReceived handles the message every time, giving you full control.

Key Takeaways

  • The Android 8.1 foreground notification issue was caused by missing a notification channel.
  • Using ProcessLifecycleOwner is the most reliable way to track app foreground/background state.
  • Data Messages give you full control over notification behavior, regardless of app state.

内容的提问来源于stack exchange,提问作者mvasco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 17:42:38