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

FirebaseMessagingService后台触发API调用 应用关闭时失效如何解决

失效原因总结

  1. 协程方案失效:FirebaseMessagingService属于短生命周期系统服务,onMessageReceived执行结束后系统会快速销毁服务实例,你自定义的协程没有和服务生命周期绑定,也没有提升服务优先级,服务销毁时协程会被直接终止,API请求来不及完成。
  2. Worker方案应用关闭时失效:绝大多数场景是因为你使用了FCM的通知类型载荷(推送内容带notification字段),当应用处于后台/被杀状态时,这类推送会直接由系统渲染通知,不会触发你重写的onMessageReceived方法,所以Worker连入队逻辑都不会执行,自然不会运行。除此之外,国内厂商的系统电池优化、后台任务限制也会导致WorkManager的任务在应用被杀后无法被正常调度。

可行解决方案

方案1:使用数据载荷+前台服务(优先级最高,最可靠)

该方案可以最大程度保证应用被杀场景下任务执行成功率:

  1. 首先修改推送载荷格式:要求后端推送时完全去掉notification字段,所有推送内容都放到data字段内,这样无论应用处于什么状态,收到推送都会走你自定义的onMessageReceived回调。
  2. 将服务临时切为前台服务执行任务:通过前台服务提升进程优先级,保证API请求完成前系统不会销毁服务,代码示例如下:
@AndroidEntryPoint
class NotificationsService @Inject constructor(
) : FirebaseMessagingService() {
    
    // 使用SupervisorJob,单个任务失败不影响其他任务
    private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

    @Inject
    lateinit var repository: NotificationRepository

    override fun onMessageReceived(message: RemoteMessage) {
        // 从data字段取参数,不要从notification取
        val notificationId: String = message.data["notificationId"] ?: ""
        val title = message.data["title"] ?: "新通知"
        val content = message.data["content"] ?: "您有一条新消息"
        // 自行定义的通知渠道ID,需要先创建通知渠道
        val channelId = "YOUR_PUSH_CHANNEL_ID"
        // 自行定义的通知ID,不要和其他通知冲突
        val foregroundNotifyId = 10086

        // 构建要展示给用户的通知
        val notification = NotificationCompat.Builder(this, channelId)
            .setContentTitle(title)
            .setContentText(content)
            .setSmallIcon(R.drawable.ic_notification_icon) // 替换为你应用的通知图标
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()
        
        // 启动前台服务,Android 12及以上需要提前申请FOREGROUND_SERVICE权限
        startForeground(foregroundNotifyId, notification)

        if (notificationId.isNotEmpty()) {
            serviceScope.launch {
                try {
                    // 执行API调用
                    repository.confirmNotification(notificationId)
                } catch (e: Exception) {
                    // 可自行添加重试逻辑
                } finally {
                    // 任务结束后停止前台状态,销毁服务
                    stopForeground(STOP_FOREGROUND_REMOVE)
                    stopSelf()
                }
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 服务销毁时取消所有未完成的协程任务
        serviceScope.cancel()
    }
}
  1. 适配国内厂商限制:引导用户给应用开启自启动权限、后台活动权限,关闭电池优化,如果集成了小米、华为等厂商推送通道,需要对应配置透传消息的接收逻辑。

方案2:Worker方案补全(如果坚持使用Worker)

如果要继续用Worker实现,需要做以下修改:

  1. 和方案1一致,必须改用纯数据载荷推送,保证onMessageReceived一定会被触发。
  2. 给Worker添加加急执行属性,避免系统延迟调度:
val worker =
    OneTimeWorkRequest.Builder(NotificationConfirmationWorker::class.java)
        .setConstraints(constraints)
        .setInputData(builder.build())
        // 加急执行,配额不足时自动降级为普通任务
        .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
        .addTag(NotificationConfirmationWorker.NOTIFICATION_WORKER_TAG)
        .build()
  1. 不要添加不必要的任务约束,减少系统拦截概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 22:15:08