Flutter后台时flutter_live_activities抛NSInternalInconsistencyException异常排查
核心异常原因
这个NSInternalInconsistencyException(提示“Sending a message before the FlutterEngine has been run”)的本质是:主FlutterEngine已进入后台挂起/非活跃状态,但插件的Live Activities监听器仍在尝试通过FlutterEventSink发送事件,此时Engine无法处理消息,直接触发崩溃。
可能的未正确销毁/处理环节
1. 缺少Engine活性判断就发送事件
插件的原生监听器触发时,没有先校验当前FlutterEngine是否处于可运行状态。即使Flutter端调用了流的销毁逻辑,当应用被系统后台挂起时,Engine可能已被暂停,此时直接调用eventSink必然触发异常。
修复方向:在原生层调用eventSink发送事件前,强制检查Engine状态,比如:
- Swift中判断
engine.runner.isExecuting - Objective-C中判断
engine.runner.isExecuting
若Engine非活跃,直接丢弃事件或缓存到应用前台后再发送。
2. 监听器注销时机未覆盖后台场景
插件的销毁逻辑可能仅在Flutter端页面销毁/流取消时注销监听器,但iOS系统可能在应用后台时主动触发Live Activities回调,此时FlutterEngine可能尚未重启,而旧的监听器仍处于注册状态。
修复方向:在iOS原生的生命周期回调中主动管理监听器:
- 在
sceneDidEnterBackground/applicationDidEnterBackground中注销Live Activities监听器 - 在
sceneWillEnterForeground/applicationWillEnterForeground中重新注册监听器
3. EventSink引用未及时释放
原生层可能对FlutterEventSink持有强引用,即使Flutter端已经关闭流,监听器仍然持有这个已失效的Sink实例,导致后台触发时仍尝试调用它。
修复方向:在Flutter流的onCancel回调中,不仅要注销监听器,还要将原生层持有的eventSink引用置为nil,彻底切断无效调用路径。
4. 后台唤醒未等待Engine初始化
当应用因Live Activities事件被后台唤醒时,FlutterEngine可能还未完成初始化流程,此时监听器直接发送事件会触发异常。
修复方向:在原生回调中先检查engine.hasRun状态,若Engine未启动,要么等待Engine初始化完成后再发送事件,要么根据业务需求直接忽略该事件。
原生层示例修复代码(Swift)
private var eventSink: FlutterEventSink? private weak var flutterEngine: FlutterEngine? // 注册Live Activities监听器 func setupLiveActivityListener(engine: FlutterEngine) { self.flutterEngine = engine // 先注销旧监听器 removeLiveActivityListener() LiveActivityManager.shared.addUpdateListener { [weak self] activityUpdate in guard let self = self, let sink = self.eventSink else { return } // 检查Engine是否处于活跃状态 guard let engine = self.flutterEngine, engine.runner.isExecuting else { // 可选:缓存事件到UserDefaults,前台后再发送 return } // 转换为Flutter可接收的字典并发送 sink(activityUpdate.toFlutterDictionary()) } } // 注销监听器并释放EventSink func removeLiveActivityListener() { LiveActivityManager.shared.removeUpdateListener() eventSink = nil } // Flutter流的回调处理 func onListen(with arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? { self.eventSink = eventSink setupLiveActivityListener(engine: self.flutterEngine!) return nil } func onCancel(with arguments: Any?) -> FlutterError? { removeLiveActivityListener() return nil } // 监听应用前后台状态 func sceneDidEnterBackground(_ scene: UIScene) { removeLiveActivityListener() } func sceneWillEnterForeground(_ scene: UIScene) { setupLiveActivityListener(engine: self.flutterEngine!) }
总结
问题根源基本是插件的原生层逻辑未覆盖后台状态下的Engine活性校验、全生命周期的监听器管理以及EventSink的及时释放这三个核心点。补全这些逻辑后,就能避免后台无有效Engine时的事件发送崩溃。
内容的提问来源于stack exchange,提问作者GGirotto

