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

收到FCM通知时FirebaseMessagingService后台上传数据失败如何解决

问题根因

  • FCM通知类型消息触发逻辑限制:若推送携带notification字段,应用退后台/被清理时,通知由系统托盘直接渲染,不会触发FirebaseMessagingService.onMessageReceived回调,你写的上传代码根本不会执行。
  • Android系统后台运行限制:Android 8.0及以上版本对后台进程的生命周期、网络访问做了严格限制,onMessageReceived回调的生命周期极短,若上传逻辑还没执行完成,Service就会被系统销毁,上传任务直接中断。
  • 没有保活机制:当前代码没有持有唤醒锁,系统可能在上传过程中进入休眠,中断网络请求。

改造方案

  1. 修改FCM消息类型
    所有推送改为纯数据类型消息,不要携带notification字段,所有通知内容都放在data字段内,由你自己的Service主动构建通知展示,保证无论应用处于什么状态,收到推送都会触发onMessageReceived回调。

  2. 使用WorkManager调度上传任务
    WorkManager是Android官方推出的后台任务调度框架,能保证任务即使应用被杀死、设备重启也会执行,完全适配系统后台限制。
    第一步:定义上传任务的Worker类

    class UploadNotificationWorker(
        context: Context,
        params: WorkerParameters
    ) : CoroutineWorker(context, params) {
        override suspend fun doWork(): Result {
            return try {
                val notifyId = inputData.getInt("notifyId", 0)
                val title = inputData.getString("title") ?: return Result.failure()
                val content = inputData.getString("content") ?: return Result.failure()
                val uid = inputData.getString("uid") ?: return Result.failure()
                val time = inputData.getString("time") ?: return Result.failure()
                val deviceId = inputData.getString("deviceId")
                val deviceName = inputData.getString("deviceName")
                val isAllowedSubLetting = inputData.getBoolean("isAllowedSubLetting", false)
                val notifyType = inputData.getInt("notifyType", 0)
    
                BackendServerHelperClass(applicationContext).saveNotification(
                    notifyId, title, content, uid, time, deviceId, deviceName, isAllowedSubLetting, notifyType
                )
                Result.success()
            } catch (e: Exception) {
                Result.retry()
            }
        }
    }
    

    第二步:替换onMessageReceived中的上传逻辑
    把原有直接调用saveNotification的代码替换为以下内容:

    val inputData = workDataOf(
        "notifyId" to System.currentTimeMillis().toInt(),
        "title" to remoteMessage.notification!!.title!!,
        "content" to remoteMessage.notification!!.body!!,
        "uid" to FirebaseAuth.getInstance().uid.toString(),
        "time" to cal.time.toString(),
        "deviceId" to deviceId,
        "deviceName" to deviceName,
        "isAllowedSubLetting" to isAllowedSubLetting.toBoolean(),
        "notifyType" to notificationType!!.toInt()
    )
    
    val uploadRequest = OneTimeWorkRequestBuilder<UploadNotificationWorker>()
        .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS)
        .setInputData(inputData)
        .build()
    
    WorkManager.getInstance(applicationContext).enqueue(uploadRequest)
    
  3. 适配Android 12以上版本
    你的现有代码中PendingIntent没有适配Android 12的可变性标记,会导致运行崩溃,修改如下:

    val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        PendingIntent.getActivity(this, 1, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
    } else {
        PendingIntent.getActivity(this, 1, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT)
    }
    
  4. 国产ROM适配
    小米、华为、OPPO等国产ROM有额外的后台限制,需要引导用户开启应用的自启动权限、后台运行白名单、后台网络权限,否则系统会直接拦截后台任务的执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 15:42:00