如何在Flutter移动端实现从REST API保存文件至本地?
在Flutter移动端实现API返回文件的下载保存功能
你需要实现的是从API获取文件流并保存到移动端本地存储的功能,以下是具体实现步骤:
1. 添加必要依赖
在pubspec.yaml中添加以下依赖,分别用于网络请求、获取本地路径和权限处理:
dependencies: flutter: sdk: flutter http: ^1.1.0 path_provider: ^2.1.1 permission_handler: ^10.2.0
执行flutter pub get安装依赖。
2. 配置存储权限
移动端需要权限才能写入本地存储,分别配置安卓和iOS的权限:
安卓
在android/app/src/main/AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_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" />
iOS
在ios/Runner/Info.plist中添加权限描述:
<key>NSPhotoLibraryAddUsageDescription</key> <string>需要访问相册以保存下载的文件</string> <key>NSPhotoLibraryUsageDescription</key> <string>需要访问相册以保存下载的文件</string>
3. 核心实现代码
结合你的HTTP请求逻辑,实现下载并保存文件的方法:
普通文件下载(小文件)
import 'dart:io'; import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; Future<void> downloadAndSaveFile() async { // 申请存储权限 final permissionStatus = await Permission.storage.request(); if (!permissionStatus.isGranted) { return; // 权限拒绝则终止操作 } // 替换为你的API地址和请求头 final apiUrl = Uri.parse("你的API接口地址"); final requestHeaders = { "Authorization": "Bearer 你的身份验证Token", // 添加其他需要的请求头 }; // 发送请求获取文件字节数据 final response = await http.get(apiUrl, headers: requestHeaders); if (response.statusCode == 200) { // 获取本地存储路径,可根据需求选择目录 final storageDir = await getExternalStorageDirectory(); final savePath = "${storageDir?.path}/downloaded_file.pdf"; // 自定义文件名和格式 // 写入文件到本地 final saveFile = File(savePath); await saveFile.writeAsBytes(response.bodyBytes); print("文件已保存至: $savePath"); // 此处可添加弹窗提示用户下载完成 } else { print("请求失败,状态码: ${response.statusCode}"); } }
流式下载(大文件,避免内存溢出)
如果API返回的是大文件,建议使用流式下载:
Future<void> downloadLargeFile() async { final permissionStatus = await Permission.storage.request(); if (!permissionStatus.isGranted) return; final apiUrl = Uri.parse("你的大文件API地址"); final requestHeaders = {"Authorization": "Bearer 你的身份验证Token"}; // 发送流式请求 final request = http.Request("GET", apiUrl); request.headers.addAll(requestHeaders); final streamedResponse = await request.send(); if (streamedResponse.statusCode == 200) { final storageDir = await getExternalStorageDirectory(); final savePath = "${storageDir?.path}/large_file.zip"; final saveFile = File(savePath); final fileSink = saveFile.openWrite(); // 将流数据写入文件 await streamedResponse.stream.pipe(fileSink); await fileSink.close(); print("大文件下载完成,路径: $savePath"); } else { print("下载失败,状态码: ${streamedResponse.statusCode}"); } }
4. 调用方法
在需要触发下载的地方(比如按钮点击事件)调用上述方法即可:
ElevatedButton( onPressed: downloadAndSaveFile, child: const Text("下载文件"), )
内容的提问来源于stack exchange,提问作者Kaan Tomruk
相关产品推荐
相关产品推荐

