Flutter后台模式下显示离线推送通知的实现方案咨询
后台网络离线通知实现方案
首先明确:Firebase无法直接实现本地网络状态的后台监听——Firebase Messaging是用于接收云端推送通知的工具,和本地网络状态感知无关。你的需求需要结合「前台服务(Android)/后台模式(iOS)」+「connectivity_plus」+「flutter_local_notifications」来实现,因为普通Flutter代码在App后台会被系统限制运行,必须通过前台服务保持进程活跃才能持续监听网络变化。
解决方案步骤
1. 添加依赖
在pubspec.yaml中补充依赖:
dependencies: connectivity_plus: ^5.0.1 flutter_local_notifications: ^16.1.0 flutter_foreground_task: ^6.1.0
2. 配置平台权限
Android(android/app/src/main/AndroidManifest.xml)
在<manifest>标签下添加权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
在<application>标签下注册前台服务:
<service android:name="com.pravera.flutter_foreground_task.service.ForegroundService" android:foregroundServiceType="location|dataSync" />
iOS(ios/Runner/Info.plist)
添加后台模式配置:
<key>UIBackgroundModes</key> <array> <string>fetch</string> <string>remote-notification</string> </array>
3. 修改代码实现
main.dart
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import 'connectivity.dart'; const AndroidNotificationChannel channel = AndroidNotificationChannel( 'high_importance_channel', 'High Importance Notifications', description: 'This channel is used for important notifications.', importance: Importance.high, playSound: true, ); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // 前台服务回调:后台执行网络监听逻辑 Future<void> startCallback() async { final MyConnectivity connectivity = MyConnectivity.instance; connectivity.initialise(); connectivity.myStream.listen((source) { final ConnectivityResult status = source.keys.first; if (status == ConnectivityResult.none) { showOfflineNotification(); } }); } // 显示离线通知 void showOfflineNotification() { flutterLocalNotificationsPlugin.show( 0, 'OFFLINE', 'No internet available', NotificationDetails( android: AndroidNotificationDetails( channel.id, channel.name, channelDescription: channel.description, importance: Importance.high, color: Colors.blue, playSound: true, icon: '@mipmap/ic_launcher', ), ), ); } Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化本地通知通道 await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel); // 初始化前台服务配置 await FlutterForegroundTask.init( androidNotificationOptions: AndroidNotificationOptions( channelId: 'foreground_task_channel', channelName: 'Network Monitor', channelDescription: 'Monitoring network status in background', channelImportance: NotificationChannelImportance.LOW, priority: NotificationPriority.LOW, iconData: const NotificationIconData( resType: ResourceType.mipmap, resPrefix: ResourcePrefix.ic, name: 'launcher', ), ), iosNotificationOptions: const IOSNotificationOptions( showNotification: true, playSound: false, ), foregroundTaskOptions: const ForegroundTaskOptions( interval: 5000, autoRunOnBoot: false, allowWakeLock: true, ), ); runApp(const MyHomePage()); } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { Map _source = {ConnectivityResult.none: false}; final MyConnectivity _connectivity = MyConnectivity.instance; List<Widget> widgetList = []; @override void initState() { super.initState(); _startForegroundTask(); _setupForegroundConnectivityListener(); } // 启动前台服务,保持后台进程活跃 void _startForegroundTask() { FlutterForegroundTask.startService( notificationTitle: 'Network Monitor', notificationText: 'Running in background', callback: startCallback, ); } // 前台状态下的网络监听(记录离线历史) void _setupForegroundConnectivityListener() { _connectivity.initialise(); _connectivity.myStream.listen((source) { setState(() => _source = source); if (_source.keys.first == ConnectivityResult.none) { showOfflineNotification(); setState(() { widgetList.add(Padding( padding: const EdgeInsets.all(5), child: Card( elevation: 3, child: Padding( padding: const EdgeInsets.all(15), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('No internet in:'), Text( DateTime.now().toString(), style: const TextStyle( color: Colors.amber, fontWeight: FontWeight.bold, ), ), ], ), ), ), )); }); } }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text("Network Monitor"), centerTitle: true, ), body: ListView( children: widgetList, ), ), ); } }
connectivity.dart(保持原逻辑,仅修正变量名冲突)
import 'dart:async'; import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; class MyConnectivity { MyConnectivity._(); static final _instance = MyConnectivity._(); static MyConnectivity get instance => _instance; final _connectivity = Connectivity(); final _controller = StreamController.broadcast(); Stream get myStream => _controller.stream; void initialise() async { ConnectivityResult result = await _connectivity.checkConnectivity(); _checkStatus(result); _connectivity.onConnectivityChanged.listen((result) { _checkStatus(result); }); } void _checkStatus(ConnectivityResult result) async { bool isOnline = false; try { final lookupResult = await InternetAddress.lookup('google.com'); isOnline = lookupResult.isNotEmpty && lookupResult[0].rawAddress.isNotEmpty; } on SocketException catch (_) { isOnline = false; } _controller.sink.add({result: isOnline}); } }
关键说明
- Android前台服务会在状态栏显示低优先级通知,这是系统强制要求,否则后台进程会被快速杀死
- iOS后台模式限制严格,网络监听无法做到完全实时,但能在App进入后台后的短周期内保持有效
- 避免在后台执行耗时操作,防止被系统判定为高耗电应用而终止进程
内容的提问来源于stack exchange,提问作者Felipe
相关产品推荐
相关产品推荐

