【问题标题】:How to download a file and store it in Downloads folder using Flutter如何使用 Flutter 下载文件并将其存储在 Downloads 文件夹中
【发布时间】:2020-01-19 13:54:35
【问题描述】:

我正在使用 Flutter 1.10.3 构建应用程序,但在将图像下载到设备的“下载”文件夹时遇到了困难。

是否可以在不使用任何第 3 部分库的情况下这样做?

【问题讨论】:

  • 用dio可以吗?
  • @AmitPrajapati 没关系
  • 你实现了我回答的下载文件功能?
  • @Amit 您编写的实现有效,但我希望实现更短。也许我已经习惯了 PHP 的函数file_get_content。为一个简单的任务添加 4 个包并编写数十行代码对我来说听起来是错误的。因此,我赞成你的问题,但我还不能接受它
  • @AmitPrajapati 确定,谢谢你的帮助 :) 解释得很好,可能会帮助很多其他人

标签: flutter


【解决方案1】:

添加一些必需的依赖项,我有一个只有 android 的测试演示。请在 IOS 设备中实现时查看file_utilspath_provider

  dio: ^3.0.0

  path_provider: ^1.3.0

  simple_permissions: ^0.1.9

  file_utils: ^0.1.3

注意:simple_permissions已断开请使用此依赖permission_handler

您需要在 android 清单文件上添加权限。

  <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" />

示例代码:

  import 'dart:io';
  import 'package:flutter/material.dart';
  import 'package:dio/dio.dart';
  import 'package:path_provider/path_provider.dart';
  import 'dart:async';
  import 'package:simple_permissions/simple_permissions.dart';
  import 'package:file_utils/file_utils.dart';
  import 'dart:math';

  void main() => runApp(Downloader());

  class Downloader extends StatelessWidget {
    @override
    Widget build(BuildContext context) => MaterialApp(
          title: "File Downloader",
          debugShowCheckedModeBanner: false,
          home: FileDownloader(),
          theme: ThemeData(primarySwatch: Colors.blue),
        );
  }

  class FileDownloader extends StatefulWidget {
    @override
    _FileDownloaderState createState() => _FileDownloaderState();
  }

  class _FileDownloaderState extends State<FileDownloader> {

    final imgUrl = "https://images6.alphacoders.com/683/thumb-1920-683023.jpg";
    bool downloading = false;
    var progress = "";
    var path = "No Data";
    var platformVersion = "Unknown";
    Permission permission1 = Permission.WriteExternalStorage;
    var _onPressed;
    static final Random random = Random();
    Directory externalDir;

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


    Future<void> downloadFile() async {
      Dio dio = Dio();
      bool checkPermission1 =
          await SimplePermissions.checkPermission(permission1);
      // print(checkPermission1);
      if (checkPermission1 == false) {
        await SimplePermissions.requestPermission(permission1);
        checkPermission1 = await SimplePermissions.checkPermission(permission1);
      }
      if (checkPermission1 == true) {
        String dirloc = "";
        if (Platform.isAndroid) {
          dirloc = "/sdcard/download/";
        } else {
          dirloc = (await getApplicationDocumentsDirectory()).path;
        }

        var randid = random.nextInt(10000);

        try {
          FileUtils.mkdir([dirloc]);
          await dio.download(imgUrl, dirloc + randid.toString() + ".jpg",
              onReceiveProgress: (receivedBytes, totalBytes) {
            setState(() {
              downloading = true;
              progress =
                  ((receivedBytes / totalBytes) * 100).toStringAsFixed(0) + "%";
            });
          });
        } catch (e) {
          print(e);
        }

        setState(() {
          downloading = false;
          progress = "Download Completed.";
          path = dirloc + randid.toString() + ".jpg";
        });
      } else {
        setState(() {
          progress = "Permission Denied!";
          _onPressed = () {
            downloadFile();
          };
        });
      }
    }

    @override
    Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text('File Downloader'),
        ),
        body: Center(
            child: downloading
                ? Container(
                    height: 120.0,
                    width: 200.0,
                    child: Card(
                      color: Colors.black,
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          CircularProgressIndicator(),
                          SizedBox(
                            height: 10.0,
                          ),
                          Text(
                            'Downloading File: $progress',
                            style: TextStyle(color: Colors.white),
                          ),
                        ],
                      ),
                    ),
                  )
                : Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(path),
                      MaterialButton(
                        child: Text('Request Permission Again.'),
                        onPressed: _onPressed,
                        disabledColor: Colors.blueGrey,
                        color: Colors.pink,
                        textColor: Colors.white,
                        height: 40.0,
                        minWidth: 100.0,
                      ),
                    ],
                  )));
  }

【讨论】:

  • 我的项目在Android X中被迁移但是插件simple_permission给出错误我发现这个插件在android x中没有被迁移
  • 您最好手动申请权限并测试此代码,如果它适用于您,然后使用任何其他权限插件。
  • 我使用了permission_handler。
  • 糟糕,忽略我上面的评论。对于 Android 10,不要使用 /sdcard/download/,而是使用“else”大小写 (await getApplicationDocumentsDirectory()).path
  • https://pub.dev/packages/simple_permissions 包已停产,不支持 NULL SAFETY。不推荐给任何人。
【解决方案2】:

如果您控制服务器,另一种选择是让用户的系统处理下载。在服务器上,您将 Content-Disposition: attachment 标头添加到响应中。在 nginx 中,您可以使用启用站点的配置文件中的 add_header 指令来执行此操作:

add_header Content-Disposition "attachment";

关于here的更多说明。

然后在 Flutter 端可以使用url_launcher 包来启动下载:

await launch('https://www.example.com/my_file.pdf');

这会将下载移交给手机上安装的浏览器。而Content-Disposition: attachment 标头会告诉浏览器它是要下载而不是显示或播放的。

此解决方案非常轻松,尽管它无法让您控制文件下载到的位置。

【讨论】:

  • 这个方法不错,但是有什么方法可以捕捉下载百分比吗?
  • @Zorro,我写了一篇关于here的文章。
  • @Suragch 您的文章仅对 Medium 中的升级帐户可见。
  • @AnoopThiruonam,感谢您的通知。 Here is the friend link.
【解决方案3】:

使用flutter_downloader有:

  • 在 android 上完成下载通知
  • 下载队列
  • 下载状态
  • 下载过程

github查看示例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 2021-04-16
    相关资源
    最近更新 更多