Flutter文件管理下载插件flutter_download_manager的使用

Flutter Download Manager

pub package pub points popularity likes

Overview

Flutter Download Manager is a Cross-Platform file downloader with Parallel and Batch Download support. Manage download tasks by URL and be notified of status and their progress. Pause, Cancel, Queue, and Resume Downloads.

Download Manager Example

Features

  • Manage download tasks by URL
  • Ability to be notified of status and progress changes
  • Partial Download Feature
  • Queue Downloads
  • Pause, Cancel, or Resume Downloads
  • Parallel File Downloads (2 or can change)
  • Support Batch download

Platforms Supported

  • Linux
  • MacOS
  • Windows
  • Android
  • iOS

Caveats

  • On desktop, it saves the file in absolute or relative paths.
  • On mobile, it saves the file in absolute or relative paths, but we should ask/ensure if the app has the required permissions.
  • It does not run in a background process, so when the Dart application closes, the manager will also shut down.

Getting Started

In your pubspec.yaml file, add:

dependencies:
  flutter_download_manager: any

Then, in your code, import:

import 'package:flutter_download_manager/flutter_download_manager.dart';

Usage

Please refer to the /example folder for a working example.

Simply Download a File

var dl = DownloadManager();
var url = "https://example.com/file.zip";
dl.addDownload(url, "./file.zip");

DownloadTask? task = dl.getDownload(url);

task?.status.addListener(() {
  print(task.status.value);
});

task?.progress.addListener(() {
  print(task.progress.value);
});

await dl.whenDownloadComplete(url);

Get Download Status

DownloadTask? task = dl.getDownload(url);

task?.status.addListener(() {
  print(task.status.value);
});

Get Download Progress

DownloadTask? task = dl.getDownload(url);

task?.progress.addListener(() {
  print(task.progress.value);
});

Await for a Task to Be Complete

DownloadTask? task = dl.getDownload(url);

await task.whenDownloadComplete();

Cancel a Task

var dl = DownloadManager();

dl.cancelDownload(url);

Pause a Task

var dl = DownloadManager();

dl.pauseDownload(url);

Resume a Task

var dl = DownloadManager();

dl.resumeDownload(url);

Download in Batch

var dl = DownloadManager();

var urls = <String>[];
urls.add(url1);
urls.add(url2);
urls.add(url3);

dl.addDownload(url1, "./file1.zip");
dl.addDownload(url2, "./file2.zip");
dl.addDownload(url3, "./file3.zip");

var downloadProgress = dl.getDownloadProgress(urls);

downloadProgress.addListener(() {
  print(downloadProgress.value);
});

await dl.whenDownloadsComplete(urls);

Cancel a Batch Download

var dl = DownloadManager();

var urls = <String>[];
urls.add(url1);
urls.add(url2);
urls.add(url3);

dl.cancelDownloads(urls);

Get Batch Download Progress

var dl = DownloadManager();

var urls = <String>[];
urls.add(url1);
urls.add(url2);

var downloadProgress = dl.getDownloadProgress(urls);

downloadProgress.addListener(() {
  print(downloadProgress.value);
});

Await for Batch Download to Complete

var dl = DownloadManager();

var urls = <String>[];
urls.add(url1);
urls.add(url2);
urls.add(url3);

await dl.whenDownloadsComplete(urls);

Future Work

  • Add in Shared Preferences to survive app shutdown

DownloadStatus

enum DownloadStatus { queued, downloading, completed, failed, paused, canceled }

Example Code

Here is a complete example demonstrating how to use flutter_download_manager in a Flutter application:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_download_manager/flutter_download_manager.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var url2 = "http://download.dcloud.net.cn/HBuilder.9.0.2.macosx_64.dmg";
  var url3 = 'https://cdn.jsdelivr.net/gh/flutterchina/flutter-in-action@1.0/docs/imgs/book.jpg';
  var url = "http://app01.78x56.com/Xii_2021-03-13%2010%EF%BC%9A41.ipa";
  var url4 = "https://jsoncompare.org/LearningContainer/SampleFiles/Video/MP4/sample-mp4-file.mp4";
  var url5 = "https://jsoncompare.org/LearningContainer/SampleFiles/Video/MP4/Sample-Video-File-For-Testing.mp4";

  var downloadManager = DownloadManager();
  var savedDir = "";

  @override
  void initState() {
    super.initState();
    getApplicationSupportDirectory().then((value) => savedDir = value.path);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Flutter Download Manager")),
      body: SingleChildScrollView(
        child: Column(
          children: [
            ListItem(
                onDownloadPlayPausedPressed: (url) async {
                  setState(() {
                    var task = downloadManager.getDownload(url);

                    if (task != null && !task.status.value.isCompleted) {
                      switch (task.status.value) {
                        case DownloadStatus.downloading:
                          downloadManager.pauseDownload(url);
                          break;
                        case DownloadStatus.paused:
                          downloadManager.resumeDownload(url);
                          break;
                      }
                    } else {
                      downloadManager.addDownload(url,
                          "$savedDir/${downloadManager.getFileNameFromUrl(url)}");
                    }
                  });
                },
                onDelete: (url) {
                  var fileName = "$savedDir/${downloadManager.getFileNameFromUrl(url)}";
                  var file = File(fileName);
                  file.delete();

                  downloadManager.removeDownload(url);
                  setState(() {});
                },
                url: url,
                downloadTask: downloadManager.getDownload(url)),
            ListItem(
                onDownloadPlayPausedPressed: (url) async {
                  setState(() {
                    var task = downloadManager.getDownload(url);

                    if (task != null && !task.status.value.isCompleted) {
                      switch (task.status.value) {
                        case DownloadStatus.downloading:
                          downloadManager.pauseDownload(url);
                          break;
                        case DownloadStatus.paused:
                          downloadManager.resumeDownload(url);
                          break;
                      }
                    } else {
                      downloadManager.addDownload(url,
                          "$savedDir/${downloadManager.getFileNameFromUrl(url)}");
                    }
                  });
                },
                onDelete: (url) {
                  var fileName = "$savedDir/${downloadManager.getFileNameFromUrl(url)}";
                  var file = File(fileName);
                  file.delete();

                  downloadManager.removeDownload(url);
                  setState(() {});
                },
                url: url2,
                downloadTask: downloadManager.getDownload(url2)),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text("Batch Downloads"),
                  ),
                  ListItem(
                      onDownloadPlayPausedPressed: (url) async {
                        setState(() {
                          var task = downloadManager.getDownload(url);

                          if (task != null && !task.status.value.isCompleted) {
                            switch (task.status.value) {
                              case DownloadStatus.downloading:
                                downloadManager.pauseDownload(url);
                                break;
                              case DownloadStatus.paused:
                                downloadManager.resumeDownload(url);
                                break;
                            }
                          } else {
                            downloadManager.addDownload(url,
                                "$savedDir/${downloadManager.getFileNameFromUrl(url)}");
                          }
                        });
                      },
                      onDelete: (url) {
                        var fileName = "$savedDir/${downloadManager.getFileNameFromUrl(url)}";
                        var file = File(fileName);
                        file.delete();

                        downloadManager.removeDownload(url);
                        setState(() {});
                      },
                      url: url3,
                      downloadTask: downloadManager.getDownload(url3)),
                  ListItem(
                      onDownloadPlayPausedPressed: (url) async {
                        setState(() {
                          var task = downloadManager.getDownload(url);

                          if (task != null && !task.status.value.isCompleted) {
                            switch (task.status.value) {
                              case DownloadStatus.downloading:
                                downloadManager.pauseDownload(url);
                                break;
                              case DownloadStatus.paused:
                                downloadManager.resumeDownload(url);
                                break;
                            }
                          } else {
                            downloadManager.addDownload(url,
                                "$savedDir/${downloadManager.getFileNameFromUrl(url)}");
                          }
                        });
                      },
                      onDelete: (url) {
                        var fileName = "$savedDir/${downloadManager.getFileNameFromUrl(url)}";
                        var file = File(fileName);
                        file.delete();

                        downloadManager.removeDownload(url);
                        setState(() {});
                      },
                      url: url4,
                      downloadTask: downloadManager.getDownload(url4)),
                  ListItem(
                      onDownloadPlayPausedPressed: (url) async {
                        setState(() {
                          var task = downloadManager.getDownload(url);

                          if (task != null && !task.status.value.isCompleted) {
                            switch (task.status.value) {
                              case DownloadStatus.downloading:
                                downloadManager.pauseDownload(url);
                                break;
                              case DownloadStatus.paused:
                                downloadManager.resumeDownload(url);
                                break;
                            }
                          } else {
                            downloadManager.addDownload(url,
                                "$savedDir/${downloadManager.getFileNameFromUrl(url)}");
                          }
                        });
                      },
                      onDelete: (url) {
                        var fileName = "$savedDir/${downloadManager.getFileNameFromUrl(url)}";
                        var file = File(fileName);
                        file.delete();

                        downloadManager.removeDownload(url);
                        setState(() {});
                      },
                      url: url5,
                      downloadTask: downloadManager.getDownload(url5)),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      TextButton(
                          onPressed: () {
                            downloadManager.addBatchDownloads(
                                [url3, url4, url5], savedDir);
                            setState(() {});
                          },
                          child: Text("Download All")),
                      TextButton(
                          onPressed: () {
                            downloadManager.pauseBatchDownloads([url3, url4, url5]);
                          },
                          child: Text("Pause All")),
                      TextButton(
                          onPressed: () {
                            downloadManager.cancelBatchDownloads([url3, url4, url5]);
                          },
                          child: Text("Cancel All")),
                    ],
                  ),
                  ValueListenableBuilder(
                      valueListenable: downloadManager
                          .getBatchDownloadProgress([url3, url4, url5]),
                      builder: (context, value, child) {
                        return Container(
                          margin: const EdgeInsets.symmetric(vertical: 4),
                          child: LinearProgressIndicator(
                            value: value,
                          ),
                        );
                      }),
                  FutureBuilder<List<DownloadTask?>?>(
                      future: downloadManager
                          .whenBatchDownloadsComplete([url3, url4, url5]),
                      builder: (BuildContext context,
                          AsyncSnapshot<List<DownloadTask?>?> snapshot) {
                        switch (snapshot.connectionState) {
                          case ConnectionState.waiting:
                            return Text(
                                'I will wait till the batch downloads have been completed');
                          default:
                            if (snapshot.hasError) {
                              return Text('Error: ${snapshot.error}');
                            } else {
                              return snapshot.data != null
                                  ? Column(children: [
                                      Text("Result"),
                                      for (var e in snapshot.data!)
                                        e != null
                                            ? Padding(
                                                padding:
                                                    const EdgeInsets.all(8.0),
                                                child: Text(
                                                    "${downloadManager.getFileNameFromUrl(e.request.url)}: ${e.status.value}"),
                                              )
                                            : Text("Not found"),
                                    ])
                                  : Text("No Downloads have been found");
                            }
                        }
                      })
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

class ListItem extends StatelessWidget {
  final Function(String) onDownloadPlayPausedPressed;
  final Function(String) onDelete;
  DownloadTask? downloadTask;
  String url = "";

  ListItem({
    Key? key,
    required this.url,
    required this.onDownloadPlayPausedPressed,
    required this.onDelete,
    this.downloadTask,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Container(
        decoration: BoxDecoration(
            border: Border.all(
              color: Colors.amber,
            ),
            borderRadius: BorderRadius.all(Radius.circular(20))),
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Expanded(
                    child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      url,
                      overflow: TextOverflow.ellipsis,
                    ),
                    if (downloadTask != null)
                      ValueListenableBuilder(
                          valueListenable: downloadTask!.status,
                          builder: (context, value, child) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(vertical: 8),
                              child: Text("$value",
                                  style: TextStyle(fontSize: 16)),
                            );
                          }),
                  ],
                )),
                downloadTask != null
                    ? ValueListenableBuilder(
                        valueListenable: downloadTask!.status,
                        builder: (context, value, child) {
                          switch (downloadTask!.status.value) {
                            case DownloadStatus.downloading:
                              return IconButton(
                                  onPressed: () {
                                    onDownloadPlayPausedPressed(url);
                                  },
                                  icon: const Icon(Icons.pause));
                            case DownloadStatus.paused:
                              return IconButton(
                                  onPressed: () {
                                    onDownloadPlayPausedPressed(url);
                                  },
                                  icon: const Icon(Icons.play_arrow));
                            case DownloadStatus.completed:
                              return IconButton(
                                  onPressed: () {
                                    onDelete(url);
                                  },
                                  icon: const Icon(Icons.delete));
                            case DownloadStatus.failed:
                            case DownloadStatus.canceled:
                              return IconButton(
                                  onPressed: () {
                                    onDownloadPlayPausedPressed(url);
                                  },
                                  icon: const Icon(Icons.download));
                          }
                          return Text("$value", style: TextStyle(fontSize: 16));
                        })
                    : IconButton(
                        onPressed: () {
                          onDownloadPlayPausedPressed(url);
                        },
                        icon: const Icon(Icons.download))
              ],
            ),
            if (downloadTask != null && !downloadTask!.status.value.isCompleted)
              ValueListenableBuilder(
                  valueListenable: downloadTask!.progress,
                  builder: (context, value, child) {
                    return Container(
                      margin: const EdgeInsets.symmetric(vertical: 4),
                      child: LinearProgressIndicator(
                        value: value,
                        color: downloadTask!.status.value == DownloadStatus.paused
                            ? Colors.grey
                            : Colors.amber,
                      ),
                    );
                  }),
            if (downloadTask != null)
              FutureBuilder<DownloadStatus>(
                  future: downloadTask!.whenDownloadComplete(),
                  builder: (BuildContext context,
                      AsyncSnapshot<DownloadStatus> snapshot) {
                    switch (snapshot.connectionState) {
                      case ConnectionState.waiting:
                        return Text(
                            'I will wait till this download has been completed');
                      default:
                        if (snapshot.hasError) {
                          return Text('Error: ${snapshot.error}');
                        } else {
                          return Text('Result: ${snapshot.data}');
                        }
                    }
                  })
          ],
        ),
      ),
    );
  }
}

This example demonstrates how to manage individual and batch downloads, including starting, pausing, resuming, and canceling downloads. It also shows how to display the download status and progress in a user interface.


更多关于Flutter文件管理下载插件flutter_download_manager的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文件管理下载插件flutter_download_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 flutter_download_manager 插件在 Flutter 中进行文件下载和管理的代码示例。这个插件允许你在 Flutter 应用中下载文件,并跟踪下载进度和状态。

首先,确保你已经在 pubspec.yaml 文件中添加了 flutter_download_manager 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_download_manager: ^x.y.z  # 请将 x.y.z 替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,是示例代码,展示如何使用 flutter_download_manager

1. 初始化下载管理器

在你的应用主文件(通常是 main.dart)中,初始化下载管理器。

import 'package:flutter/material.dart';
import 'package:flutter_download_manager/flutter_download_manager.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化下载管理器
  configureDownloadManager();

  runApp(MyApp());
}

void configureDownloadManager() {
  // 设置下载目录(可选)
  DownloadConfig.init(
    debug: true,  // 如果需要日志输出,设置为 true
    defaultSaveDir: DownloadConfig.APPLICATION_DOCUMENTS_DIR  // 或者其他目录
  ).then((_) {
    // 初始化完成
    print("Download Manager Configured");
  });
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

2. 创建一个下载按钮

在你的 HomeScreen 中,添加一个按钮来触发下载。

import 'package:flutter/material.dart';
import 'package:flutter_download_manager/flutter_download_manager.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<DownloadTask> downloads = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Download Manager Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: () => startDownload(),
              child: Text('Start Download'),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: downloads.length,
                itemBuilder: (context, index) {
                  DownloadTask task = downloads[index];
                  return ListTile(
                    title: Text('Download ID: ${task.taskId}'),
                    subtitle: Text('Status: ${task.status.toString()}'),
                    trailing: Icon(
                      Icons.file_download,
                      color: task.status == DownloadStatus.COMPLETED
                          ? Colors.green
                          : Colors.red,
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }

  void startDownload() async {
    String url = 'https://example.com/path/to/your/file.zip';
    String fileName = 'file.zip';

    try {
      DownloadTask task = await FlutterDownloadManager.instance.start(
        taskId: DateTime.now().toString(),
        url: url,
        savedDir: DownloadConfig.APPLICATION_DOCUMENTS_DIR,
        fileName: fileName,
        headers: {"Authorization": "Bearer YOUR_TOKEN"},  // 可选,如果需要添加请求头
        showNotification: true,  // 是否在下载完成时显示通知
        openFileFromNotification: true,  // 是否从通知中打开文件
      );

      // 将任务添加到列表中
      setState(() {
        downloads.add(task);
      });

      // 监听下载进度
      task.progress.listen((progress) {
        print('Download progress: ${progress.progressInPercent}%');
      });

      // 监听下载状态
      task.status.listen((status) {
        print('Download status: $status');
        
        // 更新 UI 或执行其他操作
        setState(() {});
      });

    } catch (e) {
      print('Download failed: $e');
    }
  }
}

3. 权限处理

不要忘记在 Android 和 iOS 上处理必要的权限,尤其是存储权限。对于 Android,你需要在 AndroidManifest.xml 中添加以下权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

并在运行时请求权限(如果需要)。

对于 iOS,确保在 Info.plist 中添加适当的权限描述。

注意事项

  • 确保在测试时网络连接正常。
  • 根据需要调整下载目录和文件名。
  • 处理错误和异常,确保用户体验良好。

这个示例展示了如何使用 flutter_download_manager 插件进行文件下载和基本的进度与状态管理。你可以根据需要进一步扩展和自定义。

回到顶部