收到FCM通知时FirebaseMessagingService后台上传数据失败如何解决
问题根因
- FCM通知类型消息触发逻辑限制:若推送携带
notification字段,应用退后台/被清理时,通知由系统托盘直接渲染,不会触发FirebaseMessagingService.onMessageReceived回调,你写的上传代码根本不会执行。 - Android系统后台运行限制:Android 8.0及以上版本对后台进程的生命周期、网络访问做了严格限制,
onMessageReceived回调的生命周期极短,若上传逻辑还没执行完成,Service就会被系统销毁,上传任务直接中断。 - 没有保活机制:当前代码没有持有唤醒锁,系统可能在上传过程中进入休眠,中断网络请求。
改造方案
修改FCM消息类型
所有推送改为纯数据类型消息,不要携带notification字段,所有通知内容都放在data字段内,由你自己的Service主动构建通知展示,保证无论应用处于什么状态,收到推送都会触发onMessageReceived回调。使用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)适配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) }国产ROM适配
小米、华为、OPPO等国产ROM有额外的后台限制,需要引导用户开启应用的自启动权限、后台运行白名单、后台网络权限,否则系统会直接拦截后台任务的执行。
内容的提问来源于stack exchange,提问作者Kaunain
相关产品推荐
相关产品推荐

