Firebase Messaging纯数据通知无法接收 后台onMessageReceived不触发
问题核心诱因
- 客户端逻辑硬错误:你的
onMessageReceived方法第一行就加了if(message.notification != null)的判断分支,纯数据载荷的消息不会携带notification对象,无论前后台收到消息都进不了后续处理逻辑,自然不会打日志、弹通知。另外你的代码里还有两个明显的编码错误:一是两个分类常量都命名为keyCategory1,第二个分类key重复命名会导致分类判断完全失效;二是var1/var2/notifyCategory/badgeNumber几个变量没有在方法内声明,会直接触发编译错误。 - 消息优先级配置错误:你发纯data消息时没有指定高优先级,FCM默认给普通优先级(normal)的数据消息做节流处理,应用在后台、进程被杀状态下,这类消息会被延迟投递甚至直接丢弃,根本不会唤醒应用触发Service。
- 系统权限与ROM限制:如果你的应用运行在国产定制安卓ROM上,默认会禁止应用后台自启、关联唤醒,FCM的唤醒请求会被系统直接拦截;如果targetSdkVersion >= 33,没有申请
POST_NOTIFICATIONS运行时通知权限,就算Service正常触发也弹不出通知。另外要检查AndroidManifest.xml里有没有正确声明你的FirebaseMessagingService,有没有配置com.google.firebase.MESSAGING_EVENT的intent-filter,组件有没有被误禁用。 - PendingIntent兼容问题:你代码里用的
PendingIntent.getActivities方法在Android 12及以上版本必须指定FLAG_IMMUTABLE或FLAG_MUTABLE标识,否则会直接抛异常,导致通知构建失败。
全状态拦截修改通知的实现方案
按以下步骤调整即可覆盖前台、后台、进程被杀的场景:
- 修正客户端代码
- 删掉
onMessageReceived入口处if(message.notification != null)的判断,所有收到的消息都直接走数据解析、本地内容拼接逻辑。 - 修复常量重复命名、变量未声明的编码问题,给PendingIntent加上Android 12要求的可变性flag。
- 控制
onMessageReceived内的逻辑耗时,读取本地Room数据库的操作尽量轻量,总耗时不要超过10秒,否则后台状态下应用会被系统提前回收,来不及弹出通知。
修正后的核心代码片段参考:
// 修正重复命名的常量 private val keyCategory1 = "category1key" private val keyCategory2 = "category2key" override fun onMessageReceived(message: RemoteMessage) { // 移除notification非空判断,所有消息都进处理逻辑 var msgTitle = "DEFAULT MESSAGE TITLE" var msgBody = "Default notification body text" var var1 = "" var var2 = "" var notifyCategory = "" var badgeNumber = 0 for (doc in message.data) { when (doc.key) { "someKey" -> { var1 = doc.value } "someOtherKey" -> { var2 = doc.value } "category" -> { notifyCategory = doc.value } "badge" -> { badgeNumber = doc.value.toInt() } "default_title" -> { msgTitle = doc.value } "default_body" -> { msgBody = doc.value } } } if (notifyCategory == keyCategory1) { // 结合本地存储数据格式化标题、正文 } else if (notifyCategory == keyCategory2) { // 按另一种规则格式化内容 } generateNotification(msgTitle,msgBody,badgeNumber) } private fun generateNotification(title: String, message: String, badgeNumber: Int) { val intent = Intent(this, MainActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) // 适配Android 12+的PendingIntent规则 val pendingIntentFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE } else { PendingIntent.FLAG_ONE_SHOT } val pendingIntent = PendingIntent.getActivities(this, 0, arrayOf(intent), pendingIntentFlag) // 其余通知构建逻辑保持原有即可 // ... } - 删掉
- 调整服务端消息载荷
完全移除payload里的notification块,所有自定义参数都放到data字段中,同时给安卓端消息设置高优先级,参考格式:
注意:FCM高优先级消息有配额限制,不要滥发营销类低价值消息,否则会被FCM自动降级为普通优先级,导致后台收不到。const payload = { "token": userFCMtoken, "data": { "category": "category1key", "someKey": someValue, "default_title": "兜底标题", "default_body": "兜底正文", "badge": "1" }, "android": { "priority": "high" } } - 兼容特殊场景
- Android 13及以上版本,在应用首次启动时主动申请
POST_NOTIFICATIONS运行时权限,用户拒绝的话引导到设置页手动开启。 - 面向国内用户发布的应用,需要引导用户手动开启应用的自启动、后台弹出界面权限,否则国产ROM默认会拦截FCM的后台唤醒。如果需要更高的推送到达率,建议搭配各厂商官方推送通道做兼容,FCM在国内未预装GMS的设备上完全无法工作。
- 增加兜底逻辑:data消息里携带服务端预生成的默认标题、正文,就算本地读库格式化失败,也能弹出正常通知,避免出现空白通知、无通知的情况。
- Android 13及以上版本,在应用首次启动时主动申请
内容的提问来源于stack exchange,提问作者Bend
相关产品推荐
相关产品推荐

