字节笔记本

2026年3月22日

Flutter Downloader - 文件下载管理插件

本文介绍 Flutter Downloader,一个用于创建和管理下载任务的 Flutter 插件,支持在 Android 和 iOS 平台上实现后台文件下载。

项目简介

Flutter Downloader 是由 Flutter Community 维护的一个开源插件,它为 Flutter 应用提供了强大的文件下载管理能力。该插件在 Android 平台使用 WorkManager 实现后台下载任务,在 iOS 平台则使用 NSURLSessionDownloadTask 来完成下载操作。无论应用是否在前台运行,下载任务都能可靠地执行。该项目在 GitHub 上获得了超过 900 个 Star,被超过 10,600 个项目使用,是 Flutter 生态中最受欢迎的下载管理插件之一。

需要注意的是,早期版本存在 SQL 注入漏洞,官方强烈建议升级到最新版本以获得必要的安全修复。同时,Android 11 的外部存储 API 变更也对当前实现产生了一定影响,项目正在进行重新设计以适配新的存储策略。

核心特性

  • 跨平台支持:同时支持 Android 和 iOS 平台的后台下载
  • 后台下载:应用退出后下载任务仍然可以继续执行
  • 任务管理:支持创建、暂停、恢复、取消和重试下载任务
  • 进度回调:实时获取下载进度和状态更新
  • 并发控制:可配置最大同时下载任务数量(默认为 3)
  • 通知栏集成:Android 平台支持在通知栏显示下载进度,点击通知可直接打开已下载文件
  • 请求头定制:支持自定义 HTTP 请求头(如身份认证 Token)
  • 任务持久化:下载任务信息通过 SQLite 数据库持久化存储
  • 本地化支持:支持通知消息的多语言本地化
  • HTTP 支持:可配置是否允许非 HTTPS 请求

技术栈

  • Dart:Flutter 插件的桥接层实现(21.1%)
  • Kotlin:Android 平台原生实现,基于 WorkManager(43.5%)
  • Objective-C:iOS 平台原生实现,基于 NSURLSessionDownloadTask(33.6%)
  • Swift:iOS 平台的部分支持(0.2%)
  • SQLite:下载任务信息的本地持久化存储
  • WorkManager:Android 平台的后台任务调度
  • NSURLSession:iOS 平台的后台网络请求

安装指南

添加依赖

pubspec.yaml 文件中添加以下依赖:

yaml
dependencies:
  flutter_downloader: ^1.11.8

然后运行 flutter pub get 安装依赖。

iOS 平台配置

iOS 平台需要进行以下配置:

  1. 启用后台模式:在 Xcode 中打开 ios 项目,在 Signing & Capabilities 中启用 Background Modes,并勾选 Background fetch

  2. 添加 sqlite 库:在 Xcode 中依次点击 Build Phases -> Link Binary With Libraries,添加 libsqlite3.tbd

  3. 配置 AppDelegate

Objective-C 方式:

objectivec
// AppDelegate.h
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>

@interface AppDelegate : FlutterAppDelegate
@end
objectivec
// AppDelegate.m
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
#include "FlutterDownloaderPlugin.h"

@implementation AppDelegate

void registerPlugins(NSObject<FlutterPluginRegistry>* registry) {
  if (![registry hasPlugin:@"FlutterDownloaderPlugin"]) {
     [FlutterDownloaderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterDownloaderPlugin"]];
  }
}

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  [FlutterDownloaderPlugin setPluginRegistrantCallback:registerPlugins];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

Swift 方式:

swift
import UIKit
import Flutter
import flutter_downloader

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

private func registerPlugins(registry: FlutterPluginRegistry) {
    if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
       FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!)
    }
}

Android 平台配置

Android 平台开箱即用,无需额外配置。以下为可选配置:

打开已下载文件:在 AndroidManifest.xml 中添加 FileProvider:

xml
<provider
    android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
    android:authorities="${applicationId}.flutter_downloader.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

快速开始

初始化插件

在使用任何下载功能之前,必须在 main() 函数中初始化插件:

dart
import 'package:flutter_downloader/flutter_downloader.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await FlutterDownloader.initialize(
    debug: true,       // 可选:设置为 false 禁用控制台日志输出(默认为 true)
    ignoreSsl: true    // 可选:设置为 false 禁用 HTTP 链接(默认为 false)
  );

  runApp(MyApp());
}

使用示例

创建下载任务

使用 enqueue 方法创建一个新的下载任务:

dart
final taskId = await FlutterDownloader.enqueue(
  url: 'https://example.com/file.pdf',
  headers: {'Authorization': 'Bearer your_token'},  // 可选:自定义请求头
  savedDir: '/path/to/save/directory',              // 文件保存目录
  showNotification: true,          // 在状态栏显示下载进度(Android)
  openFileFromNotification: true,  // 点击通知打开已下载文件(Android)
);

监听下载进度

下载回调函数运行在后台 Isolate 中,需要通过 ReceivePort 与 UI 线程通信:

dart
ReceivePort _port = ReceivePort();

@override
void initState() {
  super.initState();

  IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
  _port.listen((dynamic data) {
    String id = data[0];
    DownloadTaskStatus status = DownloadTaskStatus(data[1]);
    int progress = data[2];
    // 更新 UI
    setState(() { });
  });

  FlutterDownloader.registerCallback(downloadCallback);
}

@override
void dispose() {
  IsolateNameServer.removePortNameMapping('downloader_send_port');
  super.dispose();
}

@pragma('vm:entry-point')
static void downloadCallback(String id, int status, int progress) {
  final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port');
  send.send([id, status, progress]);
}

注意:@pragma('vm:entry-point') 注解必须添加在回调函数上方,以避免 Android release 模式下的 tree shaking 优化。

加载所有任务

dart
final tasks = await FlutterDownloader.loadTasks();

使用 SQL 查询加载任务

dart
final tasks = await FlutterDownloader.loadTasksWithRawQuery(
  query: 'SELECT * FROM task WHERE status=3',
);

任务控制

dart
// 取消指定任务
FlutterDownloader.cancel(taskId: taskId);

// 取消所有任务
FlutterDownloader.cancelAll();

// 暂停任务
FlutterDownloader.pause(taskId: taskId);

// 恢复任务(返回新的 taskId)
final newTaskId = await FlutterDownloader.resume(taskId: taskId);

// 重试失败的任务(返回新的 taskId)
final newTaskId = await FlutterDownloader.retry(taskId: taskId);

// 删除任务
FlutterDownloader.remove(taskId: taskId, shouldDeleteContent: false);

// 打开已下载的文件
FlutterDownloader.open(taskId: taskId);

配置最大并发任务数

iOS:在 Info.plist 中添加:

xml
<key>FDMaximumConcurrentTasks</key>
<integer>5</integer>

Android:在 AndroidManifest.xml 中配置自定义初始化器:

xml
<!-- 禁用默认初始化器 -->
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
</provider>

<!-- 声明自定义初始化器 -->
<provider
    android:name="vn.hunghd.flutterdownloader.FlutterDownloaderInitializer"
    android:authorities="${applicationId}.flutter-downloader-init"
    android:exported="false">
    <!-- 修改此数值来配置最大并发任务数 -->
    <meta-data
        android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS"
        android:value="5" />
</provider>

数据库表结构

插件使用 SQLite 存储下载任务信息,表结构如下:

sql
CREATE TABLE `task` (
  `id`          INTEGER PRIMARY KEY AUTOINCREMENT,
  `task_id`     VARCHAR(256),
  `url`         TEXT,
  `status`      INTEGER DEFAULT 0,
  `progress`    INTEGER DEFAULT 0,
  `file_name`   TEXT,
  `saved_dir`   TEXT,
  `resumable`   TINYINT DEFAULT 0,
  `headers`     TEXT,
  `show_notification`            TINYINT DEFAULT 0,
  `open_file_from_notification`  TINYINT DEFAULT 0,
  `time_created` INTEGER DEFAULT 0
);

项目链接

分享: