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

Android Firebase消息Service发送的全屏通知Intent失效问题

Android FCM推送触发全屏通知异常修复方案

问题根因

  • 全屏通知权限缺失:Android 12(API 级别 31)及以上系统,从后台组件触发全屏通知必须声明USE_FULL_SCREEN_INTENT权限。在Fragment中调用通知逻辑时应用处于前台,系统不会强制校验该权限,所以功能正常;但FCM消息服务的onMessageReceived属于后台触发场景,系统检测到权限缺失时会直接把全屏通知降级为普通通知,无法点亮屏幕、弹出全屏界面。
  • PendingIntent配置错误:代码中复用了全局注入的notificationIntent实例,没有显式指定启动的目标Activity,且从Service上下文创建PendingIntent时,原有Intent的Flags被上下文污染,系统无法匹配到已有的应用任务栈,点击通知时就会新建Activity实例,导致页面重建。
  • 锁屏显示逻辑生命周期绑定错误:点亮屏幕、解锁锁屏的逻辑只写在MainActivity的onCreate方法中,当应用退到后台、MainActivity实例未被销毁时,从通知唤起Activity不会重新执行onCreate,相关逻辑无法触发,自然不能在锁屏状态下正常展示界面。
  • 低版本窗口Flag配置错误:原代码中Android 8.0以下版本使用的窗口Flag缺少FLAG_SHOW_WHEN_LOCKED和FLAG_TURN_SCREEN_ON,本身就无法实现锁屏显示、点亮屏幕的效果,只是之前前台触发时应用本身就在运行,问题没有暴露。

修复步骤

  1. 补全AndroidManifest.xml中的权限与Activity配置
    在Manifest根节点下添加必需的权限声明:

    <!-- 全屏通知必需权限 -->
    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
    <!-- 点亮屏幕需要的唤醒锁权限 -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!-- Android 13及以上显示通知必需权限 -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    

    调整MainActivity的配置,补充锁屏显示相关属性,减少对代码动态设置的依赖:

    <activity
        android:name=".presentation.main.activities.MainActivity"
        android:screenOrientation="portrait"
        android:launchMode="singleTask"
        android:showOnLockScreen="true"
        android:turnScreenOn="true"
        android:exported="true"/>
    

    注意:部分Android 14及以上的定制ROM会在应用首次发送全屏通知时弹出用户授权弹窗,需要用户同意后才能正常使用全屏通知能力。

  2. 修正PendingIntent创建逻辑
    废弃全局复用的Intent实例,每次创建PendingIntent时显式指定启动入口Activity,配置正确的任务栈Flags,保证从任何上下文触发都能恢复已有任务栈:

    private fun createNotificationPendingIntent(): PendingIntent? {
        // 每次创建新的Intent实例,避免全局实例的Flags、上下文污染
        val intent = Intent(context, SplashActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or
                    Intent.FLAG_ACTIVITY_CLEAR_TOP or
                    Intent.FLAG_ACTIVITY_SINGLE_TOP
        }
        val pendingIntentFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        } else {
            PendingIntent.FLAG_UPDATE_CURRENT
        }
        return PendingIntent.getActivity(context, DEFAULT_REQUEST_ID, intent, pendingIntentFlags)
    }
    

    这里选择SplashActivity作为启动入口是因为它是应用的LAUNCHER Activity,系统会自动按照应用的任务栈规则导航到已存在的MainActivity,不会重复创建页面。

  3. 调整锁屏显示逻辑的生命周期绑定位置
    把点亮屏幕、显示在锁屏上层、解锁键盘的逻辑从MainActivity的onCreate移到onResume中,保证只要Activity回到前台就会执行相关逻辑,不受生命周期触发场景限制:

    override fun onResume() {
        super.onResume()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            setShowWhenLocked(true)
            setTurnScreenOn(true)
        } else {
            window.addFlags(
                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                        or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                        or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
            )
        }
    
        val keyguardManager = getSystemService(KEYGUARD_SERVICE) as KeyguardManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            keyguardManager.requestDismissKeyguard(this, null)
        }
    }
    
  4. 修复代码笔误
    原showType方法中多传入了一个重复的notification参数,删掉多余部分避免编译错误:

    override fun showType(messageTitle: String, messageBody: String, notificationType: String) {
        val notification = getNotification(messageTitle, messageBody, notificationType)
        notificationManager.notify(UUID.randomUUID().toString(), NotificationID.id, notification)
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:06:09