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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 03:10:32