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

Android应用前台运行时禁止触发Firebase推送通知

嘿,这个问题我熟!我来给你两个靠谱的解决方案,完美解决你前台不显示通知、后台正常展示的需求,比你之前试的方法要靠谱得多~

核心思路其实很简单:准确判断应用当前是否处于前台状态,只有在后台/被杀死时才触发通知构建逻辑。下面是两种实现方式,你可以根据自己的项目情况选择:

方案一:通过Activity生命周期回调判断(无需依赖Jetpack)

这种方法适合没有引入Jetpack Lifecycle组件的项目,通过监听应用内所有Activity的生命周期变化,来判断应用是否在前台。

步骤1:创建自定义Application类

新建一个继承自Application的类,实现ActivityLifecycleCallbacks接口,用来维护应用的前后台状态:

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

    @Override
    public void onCreate() {
        super.onCreate();
        // 注册Activity生命周期回调
        registerActivityLifecycleCallbacks(this);
    }

    // 以下是接口方法实现,我们只需要关注onActivityStarted和onActivityStopped
    @Override
    public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}

    @Override
    public void onActivityStarted(@NonNull Activity activity) {
        // 只要有Activity启动,就标记应用为前台状态
        isAppInForeground = true;
    }

    @Override
    public void onActivityResumed(@NonNull Activity activity) {}

    @Override
    public void onActivityPaused(@NonNull Activity activity) {}

    @Override
    public void onActivityStopped(@NonNull Activity activity) {
        // 当Activity停止时,检查当前应用是否还在前台
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses();
        if (runningProcesses != null) {
            for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
                // 匹配当前应用的包名,且进程处于前台优先级
                if (processInfo.processName.equals(getPackageName()) 
                    && processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                    isAppInForeground = true;
                    return;
                }
            }
        }
        // 走到这里说明应用已经进入后台
        isAppInForeground = false;
    }

    @Override
    public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}

    @Override
    public void onActivityDestroyed(@NonNull Activity activity) {}

    // 对外提供获取前台状态的方法
    public static boolean isAppInForeground() {
        return isAppInForeground;
    }
}

步骤2:在Manifest中注册自定义Application

打开AndroidManifest.xml,把默认的application标签的android:name属性指向我们刚才创建的MyApp:

<application
    android:name=".MyApp"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    ...>
    <!-- 其他配置 -->
</application>

步骤3:修改FCM的消息接收逻辑

在你的onMessageReceived方法中,先判断应用是否在前台,只有不在前台时才构建并显示通知:

@Override 
public void onMessageReceived(RemoteMessage remoteMessage) {
    // 先从remoteMessage中获取标题和内容(根据你的消息格式调整)
    String messageTitle = remoteMessage.getNotification() != null 
        ? remoteMessage.getNotification().getTitle() 
        : remoteMessage.getData().get("title");
    String messageBody = remoteMessage.getNotification() != null 
        ? remoteMessage.getNotification().getBody() 
        : remoteMessage.getData().get("body");

    // 关键判断:只有应用不在前台时,才显示系统通知
    if (!MyApp.isAppInForeground()) {
        // 保持你原来的通知构建逻辑
        long[] pattern = {0, 1000, 500, 1000};
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        PendingIntent pendingIntent = /* 这里是你原来的PendingIntent逻辑 */;

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE, 1, 1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(notificationId, notificationBuilder.build());
    }
    // 如果应用在前台,这里可以处理你的内部通知逻辑(比如更新UI、弹出内部弹窗等)
}

方案二:用Jetpack ProcessLifecycleOwner(更简洁高效)

如果你的项目已经引入了Jetpack组件,推荐用这个方法,它能直接跟踪整个应用的生命周期,代码更简洁,判断也更准确。

步骤1:添加依赖

在build.gradle(Module级)中添加Lifecycle Process的依赖:

dependencies {
    // 其他依赖...
    implementation "androidx.lifecycle:lifecycle-process:2.6.2"
}

步骤2:修改自定义Application类

用ProcessLifecycleOwner替换之前的Activity生命周期监听,代码简化很多:

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

    @Override
    public void onCreate() {
        super.onCreate();
        // 监听应用的全局生命周期
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new DefaultLifecycleObserver() {
            @Override
            public void onResume(@NonNull LifecycleOwner owner) {
                // 应用进入前台
                isAppInForeground = true;
            }

            @Override
            public void onPause(@NonNull LifecycleOwner owner) {
                // 应用进入后台
                isAppInForeground = false;
            }
        });
    }

    public static boolean isAppInForeground() {
        return isAppInForeground;
    }
}

步骤3:同样修改onMessageReceived逻辑

和方案一的步骤3完全一样,通过MyApp.isAppInForeground()判断是否显示通知即可。


这两种方法都能准确判断应用的前后台状态,避免了手动维护布尔值的各种坑。如果用Jetpack的话优先选方案二,代码更简洁;没有用Jetpack就选方案一,兼容性更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:14:25