Flutter Android:如何将文件保存至公共下载文件夹或应用专属文件夹?
Flutter保存文件到公共下载/自定义文件夹(解决Operation not permitted错误)
一、权限配置
Android端
- 在
android/app/src/main/AndroidManifest.xml中添加必要权限:<!-- 基础读写权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 13+ 媒体文件权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 访问所有文件权限(非媒体文件保存到公共下载需添加) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> - Android 10(API 29)及以上,需在
application标签内添加兼容配置:<application ... android:requestLegacyExternalStorage="true">
iOS端
- 在
ios/Runner/Info.plist中添加权限描述:<key>NSPhotoLibraryUsageDescription</key> <string>需要访问您的相册以保存文件</string> <key>NSDownloadsFolderUsageDescription</key> <string>需要访问下载文件夹以保存文件</string>
二、获取目标路径
使用path_provider包获取系统路径,先在pubspec.yaml添加依赖:
dependencies: path_provider: ^2.1.1
1. 公共下载文件夹路径
import 'dart:io'; import 'package:path_provider/path_provider.dart'; Future<String> getPublicDownloadPath() async { if (Platform.isAndroid) { return '/storage/emulated/0/Download'; } else { final docDir = await getApplicationDocumentsDirectory(); return '${docDir.path}/Download'; } }
Android 13+ 保存非媒体文件到公共下载需
MANAGE_EXTERNAL_STORAGE权限,需引导用户手动授权:
import 'package:permission_handler/permission_handler.dart'; Future<void> requestManageStoragePermission() async { if (await Permission.manageExternalStorage.isDenied) { await Permission.manageExternalStorage.request(); if (await Permission.manageExternalStorage.isDenied) { openAppSettings(); } } }
需添加permission_handler依赖:
dependencies: permission_handler: ^10.2.0
2. 自定义应用命名文件夹路径
此路径属于应用私有目录,无需额外权限:
import 'package:path_provider/path_provider.dart'; import 'dart:io'; Future<String> getCustomAppFolderPath() async { final externalDir = await getExternalStorageDirectory(); final customFolder = Directory('${externalDir?.path}/MyAppFiles'); if (!await customFolder.exists()) { await customFolder.create(recursive: true); } return customFolder.path; }
三、保存文件代码示例
保存字节数据到目标路径
import 'dart:io'; Future<void> saveFile(List<int> fileBytes, String fileName, String targetPath) async { final file = File('$targetPath/$fileName'); try { await file.writeAsBytes(fileBytes); print('文件保存成功:${file.path}'); } catch (e) { print('保存失败:$e'); } }
复制现有文件到目标路径
import 'dart:io'; Future<void> copyFile(String sourcePath, String targetPath, String newFileName) async { final sourceFile = File(sourcePath); final targetFile = File('$targetPath/$newFileName'); try { await sourceFile.copy(targetFile.path); print('文件复制成功:${targetFile.path}'); } catch (e) { print('复制失败:$e'); } }
四、关键注意事项
- Android 10+ 优先使用Scoped Storage,非必要不要申请
MANAGE_EXTERNAL_STORAGE权限,媒体文件可通过MediaStore API保存。 - iOS公共下载文件夹需用户通过文件应用访问,或使用
UIDocumentPickerViewController让用户选择保存位置。 - 权限测试务必在真机进行,模拟器可能存在权限模拟异常。
内容的提问来源于stack exchange,提问作者Adil Saiyad
相关产品推荐
相关产品推荐

