You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter如何从URL自动下载文件到Android/iOS下载目录

Flutter双端直链文件下载到系统Downloads目录实现方案

完全可以实现双端点击即触发、无需用户额外选路径的直链文件下载需求,核心是适配双端存储权限规则、正确获取系统公共下载目录路径即可。

依赖选型

选用轻量稳定的通用包即可实现需求,不需要引入过重的定制封装:

  • dio:处理文件下载逻辑,支持进度监听、断点续传,适配各类直链资源
  • path_provider:获取双端系统标准目录路径
  • permission_handler:适配安卓低版本存储权限申请逻辑
  • path:处理文件路径拼接、文件名解析
  • device_info_plus:准确获取安卓系统版本,避免权限适配错误

双端前置配置

Android端

在android/app/src/main/AndroidManifest.xml中添加如下配置:

  1. 仅对安卓9(API 28)及以下版本申请写存储权限,安卓10及以上采用分区存储机制,无需申请存储权限即可写入公共Downloads目录:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
<uses-permission android:name="android.permission.INTERNET"/>
  1. 若下载后需要触发打开文件的操作,额外配置FileProvider即可,纯下载保存场景不需要额外配置。

iOS端

iOS沙盒机制限制下没有全局公共Downloads目录,配置后下载文件会显示在系统「文件」App的应用专属目录中,用户可直接访问,符合App Store审核规则。在ios/Runner/Info.plist中添加:

<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>

iOS不需要额外申请存储权限,配置后写入应用Documents目录的文件会自动对系统Files可见。

核心实现代码

  1. 先在pubspec.yaml中添加依赖:
dependencies:
  flutter:
    sdk: flutter
  dio: ^5.4.0
  path_provider: ^2.1.2
  permission_handler: ^11.2.0
  path: ^1.9.0
  device_info_plus: ^9.1.2
  1. 编写下载工具方法:
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

/// [url] 直链下载地址
/// [onProgress] 可选下载进度回调,返回0-1的进度值
Future<String> downloadToSystemDownloads(
  String url, {
  void Function(double progress)? onProgress,
}) async {
  // 安卓低版本权限校验
  if (Platform.isAndroid) {
    final androidInfo = await DeviceInfoPlugin().androidInfo;
    if (androidInfo.version.sdkInt <= 28) {
      final permStatus = await Permission.storage.request();
      if (!permStatus.isGranted) {
        throw Exception('存储权限未授予,无法下载文件');
      }
    }
  }

  // 获取对应平台的下载目录
  late String downloadDir;
  if (Platform.isAndroid) {
    final extDir = await getExternalStoragePublicDirectory(StorageDirectory.downloads);
    downloadDir = extDir?.path ?? '/storage/emulated/0/Download';
  } else if (Platform.isIOS) {
    final appDocDir = await getApplicationDocumentsDirectory();
    downloadDir = appDocDir.path;
  }

  // 从直链解析文件名
  final uri = Uri.parse(url);
  final fileName = path.basename(uri.path);
  final saveFullPath = path.join(downloadDir, fileName);

  // 执行下载
  final dio = Dio();
  await dio.download(
    url,
    saveFullPath,
    onReceiveProgress: (received, total) {
      if (total > 0 && onProgress != null) {
        onProgress(received / total);
      }
    },
  );

  return saveFullPath;
}
  1. 点击触发下载的调用示例:
ElevatedButton(
  onPressed: () async {
    try {
      final savePath = await downloadToSystemDownloads(
        'https://******/image.jpg',
        onProgress: (progress) {
          // 可自行绑定进度条组件更新UI
          debugPrint('下载进度: ${(progress * 100).toStringAsFixed(0)}%');
        },
      );
      debugPrint('文件已保存至: $savePath');
    } catch (e) {
      debugPrint('下载失败: $e');
    }
  },
  child: const Text('点击下载文件'),
)

补充说明

  • 如果需要大文件后台下载能力,可替换为flutter_downloader包,该包封装了双端原生后台下载服务,同样支持配置保存路径到系统Downloads目录,适合长时下载场景
  • 安卓9及以下版本下载后如果文件未在系统文件管理器立刻显示,可主动调用MediaScanner扫描新文件路径触发系统媒体库刷新
  • iOS端下载的文件用户可在系统「文件」App中直接查看、编辑、移动,不需要额外操作,符合平台交互规范

内容的提问来源于stack exchange,提问作者Ammar Mohamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 05:01:01