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

Flutter使用Dio从URL下载PDF文件无下载进度通知问题咨询

实现Flutter Dio下载PDF带系统通知进度的方案

你当前的下载逻辑仅完成了文件写入操作,Dio本身不自带系统通知展示能力,需要配合通知插件手动触发系统通知展示下载状态,具体实现步骤如下:


1. 添加所需依赖

在pubspec.yaml的dependencies节点下新增通知插件依赖,原有依赖保持不变:

dependencies:
  flutter_local_notifications: ^16.1.0
  # 你已有的dio、fluttertoast、permission_handler、path_provider依赖无需修改

执行flutter pub get完成依赖安装。


2. 补充Android权限配置

你现有的AndroidManifest.xml已经配置了存储和网络权限,需要新增Android 13及以上版本的通知权限,在<manifest>根节点下添加如下代码:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

3. 初始化通知插件

Android 8.0及以上版本要求必须创建通知渠道才能正常展示通知,需要在应用启动时完成通知插件初始化和渠道创建,修改后的main函数代码如下:

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

// 全局声明通知插件实例
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 安卓通知初始化配置,传入应用图标
  const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher');
  const InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid);
  await flutterLocalNotificationsPlugin.initialize(initializationSettings);
  
  // 创建下载专用的通知渠道
  const AndroidNotificationChannel downloadChannel = AndroidNotificationChannel(
    'download_notify_channel', // 渠道唯一ID,后续通知需要和该ID匹配
    '文件下载通知', // 渠道名称,会在系统通知设置中展示
    description: '用于展示PDF文件下载进度', // 渠道描述
    importance: Importance.low, // 低优先级避免下载过程中频繁响铃震动
    playSound: false,
  );
  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(downloadChannel);
  
  runApp(MyApp());
}

4. 改造downloadBook方法,添加进度监听和通知更新

修改后的下载方法会在下载过程中实时更新通知进度,下载完成/失败时也会同步修改通知状态:

downloadBook({String? downloadLink, String? title}) async {
  Dio dio = Dio();
  const downloadNotifyId = 10086; // 通知唯一ID,下载全程复用该ID更新通知,避免生成多条通知

  // 先校验通知权限
  if (await Permission.postNotifications.request().isDenied) {
    Fluttertoast.showToast(msg: "请开启通知权限以查看下载进度");
    return;
  }
  // 校验存储权限
  if (await Permission.storage.request().isGranted) {
    final downloadPath = await path.getExternalStorageDirectory();
    var filePath = "${downloadPath!.path}/$title.pdf";

    try {
      await dio.download(
        downloadLink,
        filePath,
        // 监听下载进度回调
        onReceiveProgress: (receivedBytes, totalBytes) {
          if (totalBytes != -1) {
            // 计算下载百分比
            int progress = (receivedBytes / totalBytes * 100).round();
            // 构建进度通知
            AndroidNotificationDetails progressNotify = AndroidNotificationDetails(
              'download_notify_channel',
              '文件下载通知',
              channelDescription: '用于展示PDF文件下载进度',
              importance: Importance.low,
              playSound: false,
              showProgress: true,
              maxProgress: 100,
              progress: progress,
              ongoing: true, // 下载过程中禁止用户手动清除通知
            );
            NotificationDetails notifyDetails = NotificationDetails(android: progressNotify);
            // 更新通知
            flutterLocalNotificationsPlugin.show(
              downloadNotifyId,
              "正在下载 $title",
              "已完成 $progress%",
              notifyDetails,
            );
          }
        },
      );
      // 下载完成,更新通知为完成状态
      AndroidNotificationDetails finishNotify = const AndroidNotificationDetails(
        'download_notify_channel',
        '文件下载通知',
        channelDescription: '用于展示PDF文件下载进度',
        importance: Importance.defaultImportance,
        playSound: true,
        showProgress: false,
        ongoing: false,
      );
      NotificationDetails finishNotifyDetails = NotificationDetails(android: finishNotify);
      await flutterLocalNotificationsPlugin.show(
        downloadNotifyId,
        "$title 下载完成",
        "文件已保存到本地存储",
        finishNotifyDetails,
      );
    } catch (e) {
      // 下载失败,更新通知为失败状态
      AndroidNotificationDetails errorNotify = const AndroidNotificationDetails(
        'download_notify_channel',
        '文件下载通知',
        channelDescription: '用于展示PDF文件下载进度',
        importance: Importance.defaultImportance,
        playSound: true,
        showProgress: false,
        ongoing: false,
      );
      NotificationDetails errorNotifyDetails = NotificationDetails(android: errorNotify);
      await flutterLocalNotificationsPlugin.show(
        downloadNotifyId,
        "$title 下载失败",
        "请检查网络后重试",
        errorNotifyDetails,
      );
      Fluttertoast.showToast(msg: "Terjadi kesalahan. Download gagal.", timeInSecForIosWeb: 1);
    } finally {
      dio.close();
    }
  }
}

如果需要实现点击下载完成的通知直接打开PDF,可以在初始化通知时添加onDidReceiveNotificationResponse回调,配合open_file等插件跳转打开本地PDF文件即可。


内容的提问来源于stack exchange,提问作者lukman azhari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:24:00