FirebaseMessagingService后台触发API调用 应用关闭时失效如何解决
失效原因总结
- 协程方案失效:
FirebaseMessagingService属于短生命周期系统服务,onMessageReceived执行结束后系统会快速销毁服务实例,你自定义的协程没有和服务生命周期绑定,也没有提升服务优先级,服务销毁时协程会被直接终止,API请求来不及完成。 - Worker方案应用关闭时失效:绝大多数场景是因为你使用了FCM的通知类型载荷(推送内容带
notification字段),当应用处于后台/被杀状态时,这类推送会直接由系统渲染通知,不会触发你重写的onMessageReceived方法,所以Worker连入队逻辑都不会执行,自然不会运行。除此之外,国内厂商的系统电池优化、后台任务限制也会导致WorkManager的任务在应用被杀后无法被正常调度。
可行解决方案
方案1:使用数据载荷+前台服务(优先级最高,最可靠)
该方案可以最大程度保证应用被杀场景下任务执行成功率:
- 首先修改推送载荷格式:要求后端推送时完全去掉
notification字段,所有推送内容都放到data字段内,这样无论应用处于什么状态,收到推送都会走你自定义的onMessageReceived回调。 - 将服务临时切为前台服务执行任务:通过前台服务提升进程优先级,保证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() } }
- 适配国内厂商限制:引导用户给应用开启自启动权限、后台活动权限,关闭电池优化,如果集成了小米、华为等厂商推送通道,需要对应配置透传消息的接收逻辑。
方案2:Worker方案补全(如果坚持使用Worker)
如果要继续用Worker实现,需要做以下修改:
- 和方案1一致,必须改用纯数据载荷推送,保证
onMessageReceived一定会被触发。 - 给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()
- 不要添加不必要的任务约束,减少系统拦截概率。
内容的提问来源于stack exchange,提问作者RFM
相关产品推荐
相关产品推荐

