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

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标识,否则会直接抛异常,导致通知构建失败。
全状态拦截修改通知的实现方案

按以下步骤调整即可覆盖前台、后台、进程被杀的场景:

  1. 修正客户端代码
    • 删掉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)
        // 其余通知构建逻辑保持原有即可
        // ...
    }
    
  2. 调整服务端消息载荷
    完全移除payload里的notification块,所有自定义参数都放到data字段中,同时给安卓端消息设置高优先级,参考格式:
    const payload = {
        "token": userFCMtoken,
        "data": {
            "category": "category1key",
            "someKey": someValue,
            "default_title": "兜底标题",
            "default_body": "兜底正文",
            "badge": "1"
        },
        "android": {
            "priority": "high"
        }
    }
    
    注意:FCM高优先级消息有配额限制,不要滥发营销类低价值消息,否则会被FCM自动降级为普通优先级,导致后台收不到。
  3. 兼容特殊场景
    • Android 13及以上版本,在应用首次启动时主动申请POST_NOTIFICATIONS运行时权限,用户拒绝的话引导到设置页手动开启。
    • 面向国内用户发布的应用,需要引导用户手动开启应用的自启动、后台弹出界面权限,否则国产ROM默认会拦截FCM的后台唤醒。如果需要更高的推送到达率,建议搭配各厂商官方推送通道做兼容,FCM在国内未预装GMS的设备上完全无法工作。
    • 增加兜底逻辑:data消息里携带服务端预生成的默认标题、正文,就算本地读库格式化失败,也能弹出正常通知,避免出现空白通知、无通知的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 12:51:19