Flutter 中怎么下载文件

原文链接:How to download files in a flutter. - 原文作者 Dipali Thakare
本文采用意译的方式

本文将演示在 Flutter 应用中,怎么从网上下载文件。我们可以下载任何类型的文件,并将其存储到指定位置。有很多种方法实现,比如很受欢迎的包 flutter download 可以用来实现。然而,我们将会以最简单的方式来演示。

今天,我们将学习怎么将网络上的文件下载下来,并展示一个进度条。

首先,我们需要添加 Flutterdiopermission_handlerpath_provider 到我们的项目,在 pubspec.yaml 文件中添加下面的内容。

yaml 复制代码
  dio: any
  permission_handler: any
  path_provider: any

AndroidManifest.xml 文件中添加读和写的允许:

xml 复制代码
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

并且,在 AndroidManifest.xml 文件中添加 <application> 这个标签:

xml 复制代码
<application
   android:requestLegacyExternalStorage="true"

首先,创建一个 FileDownload.dart 文件。_startDownloading 方法将会创建一个文件,该文件的路径由 _getFilePath 方法返回。在安卓中,我们可以在下载的文件夹中看到这个文件。

dart 复制代码
import 'dart:io';

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

import 'package:path_provider/path_provider.dart';

class FileDownload {
  Dio dio = Dio();
  bool isSuccess = false;

  void _startDownloading(BuildContext context, final Function okCallback) async {
    String fileName = "Sample.pdf"; // 设定下载文件的名称

    String baseUrl =
        "https://file-examples.com/wp-content/uploads/2017/10/file-example_PDF_1MB.pdf"; // 远程文件路径

    String path = await _getFilePath(fileName); // 获取存储在本地的路径

    try {
      await dio.download(
        baseUrl,
        path,
        onReceiveProgress: (recivedBytes, totalBytes) {
          okCallback(recivedBytes, totalBytes);
        },
        deleteOnError: true,
      ).then((_) {
        isSuccess = true;
      });
    } catch (e) {
      print("Exception$e");
    }

    if (isSuccess) {
      Navigator.pop(context);
    }
  }

  Future<String> _getFilePath(String filename) async {
    Directory? dir;

    try {
      if (Platform.isIOS) {
        dir = await getApplicationDocumentsDirectory(); // 针对 iOS
      } else {
        dir = Directory('/storage/emulated/0/Download/');  // 针对 android
        if (!await dir.exists()) dir = (await getExternalStorageDirectory())!;
      }
    } catch (err) {
      print("Cannot get download folder path $err");
    }
    return "${dir?.path}$filename";
  }
}

下载进度对话框:

下面是进度对话框的代码。当下载一个文件时候,进度对话框会显示,用于展示下载的进度。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_downloading_file/download_file.dart';

class DownloadProgressDialog extends StatefulWidget {
  @override
  State<DownloadProgressDialog> createState() => _DownloadProgressDialogState();
}

class _DownloadProgressDialogState extends State<DownloadProgressDialog> {
  double progress = 0.0; // 当前进度

  @override
  void initState() {
    _startDownload(); // 开始下载
    super.initState();
  }

  void _startDownload() {
    FileDownload().startDownloading(context, (recivedBytes, totalBytes) {
      setState(() {
        progress = recivedBytes / totalBytes; // 接收到的字节 / 文件总的字节
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    String downloadingProgress = (progress * 100).toInt().toString();
      return AlertDialog(
        content: Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(
          margin: const EdgeInsets.symmetric(vertical: 10),
          child: const Text(
            "Downloading",
            style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
          ),
        ),
        LinearProgressIndicator( // 展示当前的下载进度
          value: progress,
          backgroundColor: Colors.grey,
          color: Colors.green,
          minHeight: 10,
        ),
        Align(
          alignment: Alignment.bottomRight,
          child: Text(
            "$downloadingProgress %",
          ),
        )
      ],
    ));
  }
}

在我们的 main.dart 文件中,使用下面的代码

main.dart 文件中,我们已经实现了一个带有下载按钮的简单代码。当点击下载按钮,我们会请求许可。一旦许可被通过,我们将可以下载文件。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_downloading_file/dowload_progress.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(MaterialApp(
    theme: ThemeData(
      primarySwatch: Colors.blueGrey,
    ),
    home: const MyHomePage(),
  ));
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Download file in flutter"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () async { // 点击下载按钮
                  bool result = await _permissionRequest();
                  if (result) { // 可以下载,则展示对话框
                    showDialog(
                        context: context,
                        builder: (dialogcontext) {
                          return DownloadProgressDialog();
                        });
                  } else {
                    print("No permission to read and write.");
                  }
                },
                child: const Text("Download File"))
          ],
        ),
      ),
    );
  }
  
  // 是否允许请求
  static Future<bool> _permissionRequest() async {
    PermissionStatus result;
    result = await Permission.storage.request();
    if (result.isGranted) {
      return true;
    } else {
      return false;
    }
  }
}

一旦文件被下载了,它可以被使用 open_filex包打开。这个包允许我们打开任何类型的文件。

输出:

初始化下载按钮

当触发下载按钮,则调出文件下载进度的弹窗

希望这篇文件能够帮到你们用 flutter 从网上下载文件。

谢谢阅读!

相关推荐
植物系青年1 分钟前
基于 Lowcode Engine 的低码平台“编码效率”提升实践
前端·低代码
海奥华22 分钟前
go中的接口返回设计思想
开发语言·后端·golang
就是我2 分钟前
开发“业务组件库”,该从哪里入手?
前端·javascript·面试
Mintopia4 分钟前
在数字画布上雕刻曲线:NURBS 的奇幻冒险之旅
前端·javascript·计算机图形学
Hacker_seagull9 分钟前
Chrome安装代理插件ZeroOmega(保姆级别)
前端·chrome
石小石Orz12 分钟前
因为没有使用路由懒加载,产生了一个难以寻找的bug
前端
Mintopia12 分钟前
Three.js 力导向图:让数据跳起优雅的华尔兹
前端·javascript·three.js
weixin_4383354014 分钟前
Spring Boot实现接口时间戳鉴权
java·spring boot·后端
寻月隐君19 分钟前
探索Web3新速度:Sonic高性能Layer-1上的BlindAuction智能合约实践
后端·web3·github
墨渊君28 分钟前
React Native 跨平台组件库实践: GlueStack UI 上手指南
前端