Flutter/Dart下载文件报错:卸载后不请求权限且无法创建文件
Flutter 卸载后无法请求存储权限导致文件下载失败的解决方案
问题重现
原本正常运行的Flutter文件下载功能,在安卓模拟器卸载应用后,出现以下错误:
Unhandled Exception: FileSystemException: Cannot create file, path = '/storage/emulated/0/Download/Salary-Sheet.xlsx'
且应用不再主动触发存储权限请求。
核心原因
- 安卓13(API 33)及以上版本对存储权限做了拆分,原
Permission.storage权限不再覆盖公共Download目录的写入权限; - 卸载应用后权限完全重置,原代码仅请求
Permission.storage,无法满足当前系统的权限要求; - 未处理权限请求被拒绝或永久拒绝的场景,导致权限获取失败后直接执行下载逻辑。
解决方案
1. 升级并适配权限请求逻辑
使用最新版permission_handler包,针对安卓13+替换为专门的下载权限:
import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/foundation.dart'; Future<bool> getStoragePermission() async { if (defaultTargetPlatform == TargetPlatform.android) { final PermissionStatus status = await Permission.downloads.request(); if (status.isGranted) { return true; } else if (status.isPermanentlyDenied) { // 引导用户前往应用设置开启权限 await openAppSettings(); return false; } else { return false; } } // iOS 保持原有存储权限请求逻辑 return await Permission.storage.request().isGranted; }
2. 确保文件目录可写
在下载前检查并创建目标目录,避免因目录不存在导致创建文件失败:
downloaddd(String downloadPath) async { var path = '$downloadPath/Salary-Sheet.xlsx'; final Directory directory = Directory(downloadPath); // 递归创建目录(包含所有父级目录) if (!await directory.exists()) { await directory.create(recursive: true); } String url = "http://salary/export/${widget.masterID}"; try { await dio.download(url, path, onReceiveProgress: (received, total) { if (total != -1) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( behavior: SnackBarBehavior.floating, content: Row( children: const [ Icon(Icons.cloud_download), SizedBox(width: 10), Text("Salary sheet has been downloaded !"), ], ), ), ); } }); } catch (e) { // 捕获并提示下载错误 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("下载失败: ${e.toString()}")), ); } }
3. 配置AndroidManifest.xml权限
根据安卓版本添加对应权限声明:
<!-- 安卓12及以下版本需要的存储权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 安卓13+访问Download目录的权限 --> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> <!-- 如需全存储访问(需Google Play审核说明用途) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
4. 可选:使用应用私有存储
如果不需要文件在系统公共Download目录显示,可改用应用私有存储,无需申请存储权限:
import 'package:path_provider/path_provider.dart'; Future<String> getDownloadPath() async { // 获取应用外部私有存储目录 final Directory? externalDir = await getExternalStorageDirectory(); return "${externalDir!.path}/Download"; }
内容的提问来源于stack exchange,提问作者swapnil mane
相关产品推荐
相关产品推荐

