Flutter下载文件到本地

本示例中使用第三方库 flutter_downloader 使用Getx状态管理

在pubspec.yaml 引入插件
dependencies: 
flutter_downloader: ^1.11.6
在mian.dart中初始化插件

await FlutterDownloader.initialize(
  debug:
  true, // optional: set to false to disable printing logs to console (default: true)
  ignoreSsl:
  true // option: set to false to disable working with http links (default: false)
);
实际使用 文件详情controller
///声明接收端口
final ReceivePort _port = ReceivePort();

///下载状态
bool isDown = false;

///本地文件路径
late String _saveLocalPath;

///文件下载ID
dynamic taskId = 0;

///下载文档
Future<void> downloaderPdf() async {
    if (filePath.isEmpty) {
      print('文件地址为空');
      return;
    }
    if (isDown) {
      print('正在下载,请勿重复点击');
      return;
    }
    ///loading
    isDown = true;
    print('下载中...');
    taskId = await FlutterDownloader.enqueue(
      url: filePath, ///文件地址
      savedDir: _saveLocalPath,
      fileName: '测试文档',
      showNotification:
          false, ///在状态栏显示下载进度(仅限Android)
      openFileFromNotification:
          false, ///点击通知打开下载的文件 (仅限Android)
    );
    ///合成本地路径 可以用来缓存 在下载记录中直接打开
    localFilePath = '$_saveLocalPath/${fileDetails.filename}';
    update();
}


///下载监听
void _bindBackgroundIsolate() {
    final isSuccess = IsolateNameServer.registerPortWithName(
      _port.sendPort,
      'downloader_send_port',
    );
    if (!isSuccess) {
      _unbindBackgroundIsolate();
      _bindBackgroundIsolate();
      return;
    }
    _port.listen((dynamic data) async {
      ///重新下载状态
      isDown = false;
      final taskId = (data as List<dynamic>)[0] as String;
      final status = data[1];
      final progress = data[2] as int;
      if (status == 3) {
        print('下载完成');
        ///打开文件
        ///删除下载任务
        await FlutterDownloader.remove(
          taskId: taskId,
          shouldDeleteContent: true,
        );
      }
      ///其他status 自行处理
    });
  }

///释放监听
void _unbindBackgroundIsolate() {
  IsolateNameServer.removePortNameMapping('downloader_send_port');
}

///注册监听事件
('vm:entry-point')
static void downloadCallback(
  String id,
  int status,
  int progress,
) {
  IsolateNameServer.lookupPortByName('downloader_send_port')
      ?.send([id, status, progress]);
}


void onInit() {
  super.onInit();
  WidgetsBinding.instance.addPostFrameCallback((_) async {
    _bindBackgroundIsolate();
    FlutterDownloader.registerCallback(downloadCallback);
    ///获取文件存储路径
    _saveLocalPath = await FileDirPath().prepareSaveDir();
    update();
  });
}

///页面关闭销毁监听

onClose() {
  _unbindBackgroundIsolate();
  super.onClose();
}

FileDirPath() 工具类 获取本地存储路径

导入对应插件

  # 文件
  path_provider: ^2.1.0
    
  # 权限请求
  permission_handler: ^11.0.0

  # 设备信息
  device_info_plus: ^9.1.1
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

class FileDirPath {
  late bool _permissionReady;

  Future<void> retryRequestPermission() async {
    final hasGranted = await _checkPermission();

    if (hasGranted) {
      await prepareSaveDir();
    }
    _permissionReady = hasGranted;
  }

  ///获取文件保存路径
  Future<String> prepareSaveDir() async {
    String localPath = (await _getSavedDir())!;
    final savedDir = Directory(localPath);
    if (!savedDir.existsSync()) {
      await savedDir.create();
    }
    return localPath;
  }

  Future<String?> _getSavedDir() async {
    String? externalStorageDirPath;
    final Directory? downloadsDir;
    if (Platform.isAndroid) {
      try {
        downloadsDir = await getDownloadsDirectory();
        externalStorageDirPath = downloadsDir!.path;
        print('externalStorageDirPath: $externalStorageDirPath');
      } catch (err, st) {
        print('failed to get downloads path: $err, $st');
        final directory = await getExternalStorageDirectory();
        externalStorageDirPath = directory?.path;
      }
    } else if (Platform.isIOS) {
      // var dir = (await _dirsOnIOS)[0]; // temporary
      // var dir = (await _dirsOnIOS)[1]; // applicationSupport
      // var dir = (await _dirsOnIOS)[2]; // library
      var dir = (await _dirsOnIOS)[3]; // applicationDocuments
      //var dir = (await _dirsOnIOS)[4]; // downloads
      dir ??= await getApplicationDocumentsDirectory();
      externalStorageDirPath = dir.absolute.path;
    }
    return externalStorageDirPath;
  }

  Future<List<Directory?>> get _dirsOnIOS async {
    final temporary = await getTemporaryDirectory();
    final applicationSupport = await getApplicationSupportDirectory();
    final library = await getLibraryDirectory();
    final applicationDocuments = await getApplicationDocumentsDirectory();
    final downloads = await getDownloadsDirectory();
    final dirs = [
      temporary,
      applicationSupport,
      library,
      applicationDocuments,
      downloads
    ];
    return dirs;
  }

  Future<bool> _checkPermission() async {
    if (Platform.isIOS) {
      return true;
    }
    if (Platform.isAndroid) {
      final info = await DeviceInfoPlugin().androidInfo;
      if (info.version.sdkInt > 28) {
        return true;
      }

      final status = await Permission.storage.status;
      if (status == PermissionStatus.granted) {
        return true;
      }

      final result = await Permission.storage.request();
      return result == PermissionStatus.granted;
    }

    throw StateError('unknown platform');
  }
}

总结
  1. flutter_downloader 集成配置参考插件官方文档
  2. **Android 存储权限变更 : **Android13以下需要声明存储权限,以上则不需要默认已授权
  3. 处理下载回调:flutter_downloader 插件提供了下载的回调函数,你可以利用这些回调来处理下载的状态变化,例如进度更新或下载完成。确保在你的应用中处理这些回调以提供更好的用户体验。
  4. 错误处理: 考虑在下载过程中处理可能的错误情况,例如网络不稳定、存储空间不足等。提供清晰的错误信息以便用户能够了解问题并可能采取相应的措施。
  5. 释放资源: 当你不再需要下载任务时,确保正确地释放资源,以避免潜在的内存泄漏
### Flutter 文件下载至自定义路径 在 Flutter 中实现文件下载保存到指定目录主要依赖于 `dio` 和 `path_provider` 插件。通过这些工具可以方便地处理网络请求以及获取应用文档目录来存储下载的内容。 #### 使用 dio 进行文件下载 为了发起 HTTP 请求并管理响应流,推荐使用 Dio 库[^1]。Dio 提供了一个简单易用的 API 来执行各种类型的 HTTP 操作,包括 GET/POST 请求和文件上传下载等功能。 安装 dio: ```yaml dependencies: flutter: sdk: flutter dio: ^5.0.0 # 版本号可能有所不同,请查阅最新版本 ``` 创建用于下载文件的服务类: ```dart import 'package:dio/dio.dart'; import 'package:path_provider/path_provider.dart'; // 获取本地路径 import 'dart:io'; class FileDownloader { final Dio _dio = Dio(); Future<String> downloadFile(String url, String fileName) async { try { Directory appDocDir = await getApplicationDocumentsDirectory(); String savePath = '${appDocDir.path}/$fileName'; Response response = await _dio.download( url, savePath, onReceiveProgress: (receivedBytes, totalBytes) { if (totalBytes != -1) { double progress = receivedBytes / totalBytes; print('Download Progress: ${(progress * 100).toStringAsFixed(0)}%'); } }, ); return savePath; // 返回保存位置 } catch (e) { throw Exception("Failed to download file"); } } } ``` 此代码片段展示了如何利用 dio 的 `download()` 方法将远程服务器上的文件下载下来,并将其存放在应用程序私有文档目录下。同时提供了进度回调以便实时跟踪下载状态。 对于 Android 平台,在某些情况下如果需要显示通知栏中的下载提示,则可以在 WebView 插件中配置相应的资源文件夹,并设置自定义的小图标以增强用户体验[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_Just_Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值