Flutter文件下载至下载文件夹插件downloadsfolder的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter文件下载至下载文件夹插件downloadsfolder的使用

Flutter Download Folder Plugin 是一个用于获取不同平台上的下载文件夹路径,并执行与文件下载相关的操作的插件。

支持平台

平台 支持版本
Android SDK 20+
iOS iOS 12+
Windows
macOS
Linux

插件功能介绍

获取下载目录路径

getDownloadDirectoryPath 函数通过平台特定的通道来获取当前平台的下载文件夹路径。

将文件复制到下载文件夹

copyFileIntoDownloadFolder 函数允许将文件复制到下载文件夹中,指定文件名并确保名称唯一以避免覆盖现有文件。

打开下载文件夹

openDownloadFolder 函数根据平台差异打开设备的下载文件夹。对于Android和iOS,它使用平台特定的通道;对于macOS和Windows,则是获取下载文件夹的路径后进行打开操作。

安装配置

pubspec.yaml 文件中添加 downloadsfolder 依赖:

dependencies:
  downloadsfolder: ^1.1.0

配置项

Android

  • 对于API 29及以上版本的Android设备,copyFileIntoDownloadFolder 方法会使用MediaStore保存文件以绕过存储权限限制。
  • 对于API 28及以下版本的设备,请确保已在 AndroidManifest.xml 中的应用元素下添加了 WRITE_EXTERNAL_STORAGE 权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>

iOS

为了启用 openDownloadFolder 功能,需要在 Info.plist 文件中添加如下键值对:

<key>UISupportsDocumentBrowser</key>
<true/>

macOS

进入项目文件夹下的 macOS/Runner/DebugProfile.entitlements 文件(对于发布版则为 'YOUR_PROJECT_NAME'Profile.entitlements),并添加以下键:

<key>com.apple.security.files.downloads.read-write</key>
<true/>

使用示例代码

下面是一个完整的演示demo,展示了如何使用这个插件的功能:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:downloadsfolder/downloadsfolder.dart';
import 'package:file_picker/file_picker.dart';
import 'package:permission_handler/permission_handler.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyApp(),
    );
  }
}

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

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

class _MyAppState extends State<MyApp> {
  String? _downloadsfolderPath;
  File? _pickedFile;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Plugin example app'),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: _getDownloadPath,
            child: const Center(
              child: Text('Get Download Path'),
            ),
          ),
          if (_downloadsfolderPath != null)
            Center(
              child: Text('Downloads Folder Path: $_downloadsfolderPath\n'),
            ),
          ElevatedButton(
            onPressed: _pickAFile,
            child: const Center(
              child: Text('Pick a File'),
            ),
          ),
          if (_pickedFile != null)
            Center(
              child: Text('Picked File Path: ${_pickedFile!.path}\n'),
            ),
          if (_pickedFile != null)
            ElevatedButton(
              onPressed: _saveFile,
              child: const Center(
                child: Text('Save Picked File into Downloads Folder'),
              ),
            ),
          ElevatedButton(
            onPressed: _openDownloadFolder,
            child: const Center(
              child: Text('Show Download Folder'),
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _getDownloadPath() async {
    Directory downloadsfolderPath;
    try {
      downloadsfolderPath = await getDownloadDirectory();
      if (!mounted) return;

      setState(() {
        _downloadsfolderPath = downloadsfolderPath.path;
      });
    } on PlatformException {
      if (!mounted) return;
      setState(() {
        _downloadsfolderPath = 'Failed to get folder path.';
      });
    }
  }

  Future<void> _pickAFile() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles();

    if (!mounted) return;

    if (result != null) {
      File file = File(result.files.single.path!);
      setState(() {
        _pickedFile = file;
      });
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('No File Has been selected'),
        ),
      );
    }
  }

  Future<void> _saveFile() async {
    bool storagePermissionGranted = true;

    if (Platform.isAndroid || Platform.isIOS) {
      storagePermissionGranted = await Permission.storage.isGranted;

      if (!storagePermissionGranted) {
        final status = await Permission.storage.request();
        storagePermissionGranted = status.isGranted;
      }
    }

    if (!storagePermissionGranted) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Failed to copy file. Storage permission is required.'),
        ),
      );
      return;
    }

    bool? success = await copyFileIntoDownloadFolder(
      _pickedFile!.path,
      basenameWithoutExtension(_pickedFile!.path),
      desiredExtension: extension(_pickedFile!.path),
    );

    if (!mounted) return;

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(success == true ? 'File copied successfully.' : 'Failed to copy file.'),
        action: success == true
            ? SnackBarAction(
                label: 'Show Download Folder',
                onPressed: _openDownloadFolder,
              )
            : null,
      ),
    );
  }

  Future<void> _openDownloadFolder() => openDownloadFolder();
}

这段代码创建了一个简单的Flutter应用程序界面,用户可以点击按钮获取下载文件夹路径、选择文件、将所选文件保存到下载文件夹以及显示下载文件夹。


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

1 回复

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


当然,我可以为你提供一个关于如何使用 downloads_folder 插件在 Flutter 中将文件下载到下载文件夹的示例代码。这个插件可以帮助你轻松地将文件保存到设备的下载目录中。

首先,你需要在 pubspec.yaml 文件中添加 downloads_folder 依赖:

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

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

接下来,在你的 Flutter 项目中,你可以使用以下代码来下载文件并将其保存到下载文件夹:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:downloads_folder/downloads_folder.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('File Download Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _downloadFile,
            child: Text('Download File'),
          ),
        ),
      ),
    );
  }
}

Future<void> _downloadFile() async {
  // 要下载的文件URL
  final String fileUrl = 'https://example.com/path/to/your/file.pdf';
  // 下载后的文件名
  final String fileName = 'downloaded_file.pdf';

  try {
    // 获取下载目录路径
    final Directory downloadsDirectory = await DownloadsFolder().getDownloadsDirectory();
    final String filePath = '${downloadsDirectory.path}/$fileName';

    // 创建文件引用
    final File file = File(filePath);

    // 使用http包下载文件
    final http.Response response = await http.get(Uri.parse(fileUrl));

    // 将下载的数据写入文件
    await file.writeAsBytes(response.bodyBytes);

    // 提示用户下载成功
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('File downloaded successfully to Downloads folder'),
      ),
    );
  } catch (e) {
    // 提示用户下载失败
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Failed to download file: $e'),
        backgroundColor: Colors.red,
      ),
    );
  }
}

代码解释:

  1. 依赖导入

    • downloads_folder:用于获取下载目录路径。
    • path_provider:虽然在这个示例中未直接使用,但通常用于获取应用目录路径(这个示例中我们用不到它,但有时候会有用)。
    • http:用于发送HTTP请求下载文件。
  2. 主应用

    • MyApp:根Widget,包含一个按钮,点击按钮调用 _downloadFile 函数。
  3. 文件下载函数

    • _downloadFile:这个函数首先获取下载目录的路径,然后创建一个文件引用,接着使用 http 包发送GET请求下载文件,最后将下载的数据写入文件。
  4. 错误处理

    • 使用 try-catch 块捕获并处理任何可能的异常,通过SnackBar向用户显示下载成功或失败的消息。

请注意,你需要确保 AndroidManifest.xmlInfo.plist 中有适当的权限声明,以允许应用访问存储。对于Android,通常需要 WRITE_EXTERNAL_STORAGE 权限(从Android 10开始,Scoped Storage生效,你可能需要请求 MANAGE_EXTERNAL_STORAGE 或使用MediaStore API,但 downloads_folder 插件通常会处理这些细节)。对于iOS,你需要确保应用有权限写入文件。

希望这个示例能帮助你理解如何使用 downloads_folder 插件在Flutter应用中下载文件到下载文件夹。

回到顶部