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

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

simple_downloader 是一个用于在Flutter项目中处理HTTP文件下载的简单且易于使用的插件。

安装

在你的Flutter项目的pubspec.yaml文件中添加依赖:

dependencies:
...
simple_downloader: ^0.0.3

然后运行flutter pub get来获取新的依赖项。

导入包

在你的Dart文件中导入simple_downloader包:

import 'package:simple_downloader/simple_downloader.dart';

初始化

首先,你需要初始化SimpleDownloader对象,并设置一些基本参数。以下是一个完整的示例代码:

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart' as path;
import 'package:simple_downloader/simple_downloader.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late SimpleDownloader _downloader;

  double _progress = 0.0;
  int _offset = 0;
  int _total = 0;
  DownloadStatus _status = DownloadStatus.undefined;
  DownloaderTask _task = const DownloaderTask(
    url:
        "https://images.unsplash.com/photo-1615220368123-9bb8faf4221b?ixlib=rb-1.2.1&amp;dl=vadim-kaipov-f6jkAE1ZWuY-unsplash.jpg&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb",
    fileName: "images_downloaded.jpg",
    bufferSize:
        1024, // 如果未设置bufferSize,默认值为64(64Kb)
  );

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

  @override
  void dispose() {
    _downloader.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('文件下载管理示例'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Container(
            height: 150,
            width: double.maxFinite,
            decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(20),
                boxShadow: const [
                  BoxShadow(
                    color: Colors.black12,
                    offset: Offset(0, 3),
                    spreadRadius: 3,
                    blurRadius: 3,
                  )
                ]),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                ListTile(
                  visualDensity:
                      const VisualDensity(horizontal: -4, vertical: 0),
                  title: Text(_task.fileName ?? ""),
                  subtitle: labelStatus,
                  trailing: trailingIcon,
                ),
                const SizedBox(height: 25.0),
                Padding(
                  padding: const EdgeInsets.only(left: 15.0, right: 15.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.end,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text("${_offset ~/ 1024} Kb / ${_total ~/ 1024} Kb",
                              textAlign: TextAlign.right),
                          Text("${_progress.floor()} %",
                              textAlign: TextAlign.right),
                        ],
                      ),
                      const SizedBox(height: 5),
                      LinearProgressIndicator(
                        value: _progress / 100,
                      )
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Future<void> init() async {
    final pathFile = (await path.getExternalStorageDirectory())!.path;
    if (!mounted) return;

    _task = _task.copyWith(
      downloadPath: pathFile,
    );

    _downloader = SimpleDownloader.init(task: _task);

    _downloader.callback.addListener(() {
      setState(() {
        _progress = _downloader.callback.progress;
        _status = _downloader.callback.status;
        _total = _downloader.callback.total;
        _offset = _downloader.callback.offset;
      });
    });
  }

  Widget get labelStatus {
    switch (_status) {
      case DownloadStatus.undefined:
        return const Text("等待中...");
      case DownloadStatus.completed:
        return const Text("下载完成");
      case DownloadStatus.failed:
        return const Text("下载失败");
      case DownloadStatus.paused:
        return const Text("下载暂停");
      case DownloadStatus.deleted:
        return const Text("文件已删除");
      case DownloadStatus.canceled:
        return const Text("下载取消");
      default:
        return const Text("正在下载");
    }
  }

  Widget? get trailingIcon {
    if (_status == DownloadStatus.undefined ||
        _status == DownloadStatus.deleted) {
      return IconButton(
        splashRadius: 20,
        onPressed: () => _downloader.download(),
        constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
        icon: const Icon(
          Icons.play_arrow,
        ),
      );
    }
    if (_status == DownloadStatus.running ||
        _status == DownloadStatus.resume ||
        _status == DownloadStatus.retry) {
      return Row(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          IconButton(
            splashRadius: 20,
            onPressed: () => _downloader.pause(),
            constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
            icon: const Icon(
              Icons.pause,
              color: Colors.green,
            ),
          ),
          IconButton(
            splashRadius: 20,
            onPressed: () => _downloader.cancel(),
            constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
            icon: const Icon(
              Icons.close,
              color: Colors.red,
            ),
          ),
        ],
      );
    }
    if (_status == DownloadStatus.paused) {
      return Row(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          IconButton(
            splashRadius: 20,
            onPressed: () => _downloader.resume(),
            constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
            icon: const Icon(
              Icons.play_arrow,
              color: Colors.blue,
            ),
          ),
          IconButton(
            splashRadius: 20,
            onPressed: () => _downloader.cancel(),
            constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
            icon: const Icon(
              Icons.close,
              color: Colors.red,
            ),
          ),
        ],
      );
    }

    if (_status == DownloadStatus.completed) {
      return Row(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          IconButton(
            tooltip: "打开文件",
            splashRadius: 20,
            onPressed: () async {
              _downloader.open().then(
                (isSuccess) {
                  if (!isSuccess!) {
                    showMessage(context, "无法打开下载的文件。");
                  }
                },
              );
            },
            constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
            icon: const Icon(
              Icons.file_open,
              color: Colors.green,
            ),
          ),
          IconButton(
            tooltip: "删除文件",
            splashRadius: 20,
            onPressed: () => _downloader.delete(),
            constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
            icon: const Icon(
              Icons.delete,
              color: Colors.red,
            ),
          ),
        ],
      );
    }

    if (_status == DownloadStatus.failed ||
        _status == DownloadStatus.canceled) {
      return Row(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            IconButton(
              splashRadius: 20,
              onPressed: () => _downloader.retry(),
              constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
              icon: const Icon(
                Icons.refresh,
                color: Colors.green,
              ),
            ),
            IconButton(
              splashRadius: 20,
              onPressed: () => _downloader.restart(),
              constraints: const BoxConstraints(minHeight: 32, minWidth: 32),
              icon: const Icon(
                Icons.restart_alt,
                color: Colors.red,
              ),
            ),
          ]);
    }

    return null;
  }

  Future<void> showMessage(
    BuildContext context,
    String message,
  ) async {
    final size = MediaQuery.of(context).size;
    return showModalBottomSheet(
        elevation: 2,
        isDismissible: false,
        enableDrag: false,
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(30), topRight: Radius.circular(30)),
        ),
        context: context,
        builder: (builder) {
          return SizedBox(
            height: 250,
            child: Stack(children: [
              Positioned(
                top: 10,
                right: 10,
                child: IconButton(
                  splashRadius: 25,
                  onPressed: () => Navigator.pop(context),
                  icon: const Icon(
                    Icons.close,
                    size: 25,
                  ),
                ),
              ),
              Center(
                child: Container(
                  constraints: BoxConstraints(
                    maxWidth: 0.8 * size.width,
                  ),
                  child: Text(
                    message,
                    textAlign: TextAlign.center,
                    style: const TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ),
              ),
              Positioned(
                bottom: 20,
                right: 20,
                left: 20,
                child: ElevatedButton(
                  child: const Text(
                    "确定",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w600),
                  ),
                  onPressed: () => Navigator.pop(context),
                ),
              ),
            ]),
          );
        });
  }
}

开始下载

要开始下载,请调用download()方法:

_downloader.download();

暂停下载

要暂停下载,请调用pause()方法:

_downloader.pause();

恢复下载

要恢复下载,请调用resume()方法:

_downloader.resume();

取消下载

要取消下载,请调用cancel()方法:

_downloader.cancel();

重试下载

要重试下载,请调用retry()方法:

_downloader.retry();

重新启动下载

要重新启动下载,请调用restart()方法:

_downloader.restart();

打开下载的文件(仅支持Android)

如果下载成功并希望打开文件,请调用open()方法:

_downloader.open().then(
  (isSuccess) {
    if (!isSuccess!) {
      print(context, "Failed to open downloaded file.");
    }
  },
);

Android集成

为了处理点击事件以打开下载的文件,你需要进行一些额外的配置。在AndroidManifest.xml中添加以下内容:

<application>
        ...
        <provider
            android:name="adry.app.simple_downloader.FileProvider"
            android:authorities="${applicationId}.simple_downloader.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path"/>
        </provider>  
<application>

如果你的应用需要安装APK文件,还需要添加以下权限:

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

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

1 回复

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


当然,以下是如何在Flutter项目中使用simple_downloader插件来进行文件下载管理的示例代码。这个插件提供了在后台下载文件的功能,并支持暂停和恢复下载。

首先,确保你的Flutter项目已经添加了simple_downloader依赖。在你的pubspec.yaml文件中添加以下依赖:

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

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

接下来,以下是一个完整的示例代码,展示如何使用simple_downloader进行文件下载管理:

import 'package:flutter/material.dart';
import 'package:simple_downloader/simple_downloader.dart';
import 'package:path_provider/path_provider.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Downloader Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final SimpleDownloader _downloader = SimpleDownloader();
  String _downloadStatus = "No download started.";

  @override
  void initState() {
    super.initState();
    // 初始化下载器
    _downloader.initialize().then((_) {
      // 监听下载状态变化
      _downloader.downloadStatusStream.listen((status) {
        setState(() {
          _downloadStatus = status;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Downloader Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _downloadStatus,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                // 获取应用文档目录
                Directory appDocDir = await getApplicationDocumentsDirectory();
                String filePath = appDocDir.path + "/example.zip";

                // 开始下载
                var taskId = await _downloader.start(
                  url: "https://example.com/largefile.zip",
                  savedDir: appDocDir.path,
                  fileName: "example.zip",
                  showNotification: true,
                  openFileFromNotification: true,
                );

                setState(() {
                  _downloadStatus = "Download started with taskId: $taskId";
                });
              },
              child: Text('Start Download'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 释放资源
    _downloader.dispose();
    super.dispose();
  }
}

代码说明:

  1. 依赖安装:在pubspec.yaml文件中添加simple_downloader依赖。
  2. 初始化下载器:在initState方法中初始化下载器并监听下载状态变化。
  3. 开始下载:点击按钮时,获取应用文档目录并调用_downloader.start方法开始下载文件。
  4. 显示下载状态:通过_downloader.downloadStatusStream监听下载状态并更新UI。

注意事项:

  • 确保你提供的URL是有效的,并且服务器支持断点续传,因为simple_downloader依赖于这个功能来实现暂停和恢复下载。
  • 根据需要调整文件保存路径和文件名。
  • 在实际项目中,你可能需要处理更多的错误情况和用户交互,比如下载失败时的重试机制。

这个示例展示了基本的文件下载管理功能,你可以根据实际需求进行扩展和修改。

回到顶部