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

Flutter中FCM推送无法在后台/锁屏更新Live Activities问题

问题分析与解决方案

问题根源

  1. iOS后台/锁屏状态下,Flutter的FCM后台消息处理器handleBackgroundMessage执行环境受限:系统会限制Flutter引擎在后台的活跃时间,甚至直接挂起进程,导致无法可靠调用Live Activities插件完成更新。
  2. 代码逻辑不符合iOS Live Activities的官方更新机制:后台状态下的Live Activities更新,必须通过iOS原生的推送服务扩展实现,而非依赖Flutter的后台回调。
  3. 全局变量soc无法持久化:后台消息处理是独立进程,全局变量会被重置,无法实现累加更新。

核心修复方案:使用iOS推送服务扩展处理Live Activities更新

1. 添加Notification Service Extension

在Xcode中给Flutter项目新增Notification Service Extension目标(命名如LiveActivityUpdater),并确保该扩展与主App使用相同的App Group ID(即你的group.new_activity):

  • 在扩展的Info.plist中添加AppGroups权限,包含目标App Group ID。
  • 确保扩展的签名配置与主App一致。

2. 编写扩展更新逻辑

替换NotificationService.swift的代码,通过扩展直接处理Live Activities更新:

import UserNotifications
import ActivityKit

// 定义Live Activity的属性和状态(需与Flutter端对应)
struct LiveActivityAttributes: ActivityAttributes {
    public struct ContentState: Codable, Hashable {
        var soc: String
    }
}

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        guard let content = bestAttemptContent,
              let socValue = content.userInfo["soc"] as? String,
              let activityId = UserDefaults(suiteName: "group.new_activity")?.string(forKey: "liveActivityId") else {
            contentHandler(content)
            return
        }
        
        // 匹配并更新目标Live Activity
        Task {
            for activity in Activity<LiveActivityAttributes>.activities {
                if activity.id == activityId {
                    await activity.update(using: LiveActivityAttributes.ContentState(soc: socValue))
                    break
                }
            }
        }
        
        contentHandler(content)
    }
    
    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

3. 调整FCM推送Payload

推送时必须携带mutable-content: 1,触发iOS调用推送服务扩展,示例Payload:

{
  "to": "你的FCM设备令牌",
  "mutable_content": 1,
  "data": {
    "soc": "50",
    "activityId": "存储的Live Activity ID"
  },
  "notification": {
    "title": "SOC更新",
    "body": "当前SOC: 50%"
  }
}

4. 修正Flutter端代码

  • 删除handleBackgroundMessage中更新Live Activities的逻辑,后台更新不再依赖Flutter。
  • 使用支持App Group的存储插件(如shared_preferences_app_group),将Live Activity ID存入App Group的UserDefaults,确保扩展能读取:
// 创建Live Activity时存储ID到App Group
final activityId = await _liveActivitiesPlugin.createActivity(
  LiveActivityAttributes(soc: "0"),
);
final appGroupPrefs = await SharedPreferencesAppGroup().getInstance(groupId: "group.new_activity");
await appGroupPrefs.setString('liveActivityId', activityId);

5. 关键注意事项

  • 确认主App和扩展都已正确配置App Group权限,且签名通过。
  • Live Activities的更新推送必须包含mutable-content: 1,否则iOS不会触发扩展。
  • 禁止在Flutter后台消息回调中执行Live Activities更新操作,iOS后台对Flutter引擎的运行有严格限制,无法保证可靠性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:58:24