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

Flutter中使用universal_html包的EventSource时,锁定手机后连接自动关闭导致无法接收数据的问题

解决Flutter中EventSource锁屏后自动断开的问题

这个问题我之前做Flutter SSE项目时踩过坑!核心原因是手机锁屏后,系统会触发后台资源限制——不管是Android还是iOS,都会优先暂停非前台应用的网络连接或者直接挂起进程,导致你用universal_html实现的EventSource连接被强制断开了。结合你的代码,我给你几个可行的解决方案:

1. 配置后台保活权限与进程保活

Android端配置

  • 首先在AndroidManifest.xml中添加必要权限:
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
  • 用**前台服务(Foreground Service)**来保持进程活跃:因为后台进程很容易被系统杀死,前台服务会在状态栏显示一个通知,让系统认为应用在执行重要任务,从而避免被回收。你可以在连接EventSource前启动前台服务,断开后停止。
  • 注意:部分国产厂商(小米、华为、OPPO等)有自己的后台管控,需要引导用户把应用加入“后台白名单”或者“自启动权限”,否则前台服务也可能被强制关闭。

iOS端配置

  • 在Xcode的项目配置中,开启Background Modes里的Remote notifications或Background fetch权限。
  • iOS对后台限制非常严格,SSE连接很难在后台长期保持,更推荐用APNs推送通知:当服务器有新数据时,先发送推送通知给客户端,客户端收到通知后再主动拉取数据或者重新建立EventSource连接。

2. 替换universal_html的EventSource为原生实现

universal_html的EventSource是纯Dart模拟的,在后台环境下没有原生系统的适配支持。你可以改用原生封装的SSE库,或者自己通过MethodChannel调用Android/iOS原生的EventSource组件,原生实现对后台网络的兼容性更好。

3. 优化重连逻辑,适配后台断开场景

你的现有重连逻辑比较简单,建议增加指数退避重连(避免频繁重试消耗资源),同时调整监听参数:

int _retryDelay = 1; // 初始重试延迟1秒

void connectSession() {
  // 可选:先检查网络状态(可以用connectivity_plus库实现)
  // final connectivityResult = await Connectivity().checkConnectivity();
  // if (connectivityResult == ConnectivityResult.none) { ... }

  eventSource = EventSource(Uri.parse(sseUrl).toString());
  print("Attempting to connect to EventSource...");

  eventSource.onMessage.listen((event) {
    // 处理收到的消息
    _retryDelay = 1; // 成功接收消息后重置重试延迟
  }, onError: (error) {
    print("EventSource error occurred: $error");
    _handleDisconnect();
  }, onDone: () {
    print("EventSource connection closed");
    _handleDisconnect();
  }, cancelOnError: false); // 改为false,避免错误时取消整个监听

  eventSource.onError.listen((event) {
    print("EventSource error event: $event");
    _handleDisconnect();
  });
}

void _handleDisconnect() {
  if (eventSource != null) {
    eventSource.close();
    eventSource = null;
  }
  eventErrorMessage("Connection lost, retrying in $_retryDelay seconds", context);
  this.isListening = false;

  // 指数退避重连:每次延迟翻倍,最大不超过32秒
  Future.delayed(Duration(seconds: _retryDelay), () {
    connectSession();
    _retryDelay = _retryDelay * 2;
    if (_retryDelay > 32) _retryDelay = 32;
  });
}

额外注意点

  • 不要在后台执行过多耗时操作,否则会被系统判定为“不良行为”,直接终止进程。
  • 如果你的业务对实时性要求极高,Android端可以考虑用WorkManager配合周期性任务,定期检查连接状态;iOS端则优先依赖推送通知触发临时后台任务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 17:17:31