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
相关产品推荐
相关产品推荐

