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

Flutter应用关闭时如何维持WebSocket连接并接收服务端消息?

Flutter后台持续运行与WebSocket消息推送实现

一、核心原理:移动平台的后台限制逻辑

不管Android还是iOS,系统都把「省电」和「资源管控」放在首位,普通App退到后台后很快会被冻结甚至杀死——直接在Flutter主代码里跑WebSocket,App一后台就会断连,根本没法持续接收消息。

Android侧规则

  • 从Android 8.0(API 26)开始,普通后台进程会被系统优先回收,只有前台服务能获得持续运行权限:前台服务必须在状态栏显示通知,告知用户App在后台运行,用户可手动关闭,关闭后服务停止。
  • Android 12之后,前台服务的启动需要用户授权,无法偷偷启动。

iOS侧规则

  • iOS对后台管控更严格,普通App后台最多存活5-10分钟就会被挂起,仅允许音频播放、实时定位、VoIP语音通话等特定场景申请后台持续运行权限。
  • 若想通过WebSocket维持长连,只能走VoIP模式,但Apple审核标准严苛,非语音类App使用该模式大概率会被拒。

另外,WebSocket本身基于TCP长连接,但移动网络存在基站切换、休眠等不稳定情况,即便App在后台未被杀死,连接也极易断开,必须添加自动重连逻辑。

二、具体实现方案

方案1:后台服务维持WebSocket长连(适合必须实时长连的场景)

使用flutter_background_service插件,在Android和iOS上创建独立后台服务,运行Dart代码维持WebSocket连接。

1. 添加依赖

在pubspec.yaml中引入所需包:

dependencies:
  flutter_background_service: ^4.2.2
  web_socket_channel: ^2.4.0
  flutter_local_notifications: ^16.1.0

2. Android配置

  • 打开android/app/src/main/AndroidManifest.xml,添加权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
  • 在<application>标签内注册后台服务:
<service
    android:name="id.flutter.flutter_background_service.BackgroundService"
    android:foregroundServiceType="dataSync" />

3. iOS配置

若需使用VoIP模式(风险高,谨慎选择),打开ios/Runner/Info.plist添加:

<key>UIBackgroundModes</key>
<array>
    <string>voip</string>
</array>

若仅需后台短时间存活,无需添加该配置,但WebSocket仍会随App后台冻结而断开。

4. 编写后台逻辑

初始化后台服务,维持WebSocket连接并在收到消息时触发本地通知:

import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();

void initBackgroundService() {
  final service = FlutterBackgroundService();
  service.configure(
    iosConfiguration: IosConfiguration(
      autoStart: true,
      onForeground: _onServiceStart,
      onBackground: _onIosBackground,
    ),
    androidConfiguration: AndroidConfiguration(
      onStart: _onServiceStart,
      autoStart: true,
      isForegroundMode: true, // 必须开启前台模式,否则会被系统杀死
      notificationTitle: "后台连接中",
      notificationContent: "正在同步服务端消息",
    ),
  );
}

// 后台服务入口,必须添加注解保证编译时不被移除
@pragma('vm:entry-point')
void _onServiceStart(ServiceInstance service) async {
  await _initNotifications();

  // 连接Rust服务端WebSocket
  var channel = WebSocketChannel.connect(Uri.parse('ws://你的Rust服务端地址'));

  // 监听服务端消息
  channel.stream.listen(
    (message) => _showNotification("服务端消息", message.toString()),
    onDone: () => _reconnectWebSocket(),
    onError: (_) => _reconnectWebSocket(),
  );

  // 监听停止服务指令
  service.on('stop').listen((_) => service.stopSelf());
}

// iOS后台回调
@pragma('vm:entry-point')
Future<bool> _onIosBackground(ServiceInstance service) async {
  return true;
}

// 重连WebSocket
void _reconnectWebSocket() {
  Future.delayed(const Duration(seconds: 5), () {
    final channel = WebSocketChannel.connect(Uri.parse('ws://你的Rust服务端地址'));
  });
}

// 初始化本地通知
Future<void> _initNotifications() async {
  const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
  const DarwinInitializationSettings iosSettings = DarwinInitializationSettings();
  const InitializationSettings settings = InitializationSettings(android: androidSettings, iOS: iosSettings);
  await _notificationsPlugin.initialize(settings);
}

// 显示本地通知
void _showNotification(String title, String body) async {
  const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
    'channel_id',
    '服务端消息',
    importance: Importance.max,
    priority: Priority.high,
  );
  const DarwinNotificationDetails iosDetails = DarwinNotificationDetails();
  const NotificationDetails details = NotificationDetails(android: androidDetails, iOS: iosDetails);
  await _notificationsPlugin.show(0, title, body, details);
}

方案2:系统推送服务替代WebSocket(更推荐,合规且省电)

大部分场景无需维持WebSocket长连,使用系统级推送服务是更优选择:

  • Android用FCM(Firebase Cloud Messaging),iOS用APNs(Apple Push Notification service)。
  • Rust服务端直接调用FCM/APNs的API发送消息,系统负责将消息推送给App,即便App完全关闭也能收到通知。
  • 该方式无需处理后台运行逻辑,系统兜底,更省电且符合平台规范。

Rust后端可使用firebase-admin crate(适配FCM)或apns2 crate(适配APNs)实现推送逻辑。

三、关键注意事项

  • Android前台服务必须显示通知,用户可手动关闭,关闭后服务停止。
  • iOS的VoIP模式审核严格,非语音类App请勿使用,避免审核被拒。
  • WebSocket必须添加自动重连逻辑,适配移动网络的不稳定特性。
  • 后台代码需轻量化,避免消耗过多资源,否则仍会被系统终止。

内容的提问来源于stack exchange,提问作者LucioleMaléfique

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:01:28