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,本身就无法实现锁屏显示、点亮屏幕的效果,只是之前前台触发时应用本身就在运行,问题没有暴露。
修复步骤
补全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会在应用首次发送全屏通知时弹出用户授权弹窗,需要用户同意后才能正常使用全屏通知能力。
修正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,不会重复创建页面。
调整锁屏显示逻辑的生命周期绑定位置
把点亮屏幕、显示在锁屏上层、解锁键盘的逻辑从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) } }修复代码笔误
原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
相关产品推荐
相关产品推荐

