Flutter在Android 11中下载PDF文件时遭遇FileSystemException(errno=1)权限异常求助
解决Android 11下文件写入权限异常(Operation not permitted, errno=1)
针对你遇到的问题,核心原因是Android 11引入的Scoped Storage机制,以及MANAGE_EXTERNAL_STORAGE权限的特殊管控逻辑,下面是具体的解决方案:
1. 修正MANAGE_EXTERNAL_STORAGE权限的请求逻辑
MANAGE_EXTERNAL_STORAGE是Android 11+的特殊权限,无法通过permission_handler的常规request()方法弹出系统授权弹窗,必须引导用户到应用设置页面手动开启权限。你需要修改权限请求代码:
Map<Permission, PermissionStatus> result = await [ Permission.storage, Permission.mediaLibrary ].request(); // 单独处理MANAGE_EXTERNAL_STORAGE权限 if (Platform.isAndroid && (await Permission.manageExternalStorage.status).isDenied) { // 引导用户到应用设置页开启权限 await openAppSettings(); // 重新检查权限状态 bool hasManagePerm = await Permission.manageExternalStorage.request().isGranted; if (!hasManagePerm) { Components.customSnackBar(context, "需要授予所有文件访问权限才能下载"); return; } } // 确认所有必要权限都已授予 bool hasStorage = result[Permission.storage].isGranted; bool hasMediaLib = result[Permission.mediaLibrary].isGranted; bool hasManage = await Permission.manageExternalStorage.status.isGranted; if (hasStorage && hasMediaLib && hasManage) { // 执行后续下载逻辑 }
2. 确保目标目录存在且可访问
你的自定义路径/storage/emulated/0/documents/download folder需要确认是否已正确创建,并且应用有访问权限。在Utility.makeAndGetDownloadFolder()方法中,添加目录创建的异常捕获:
static Future<String> makeAndGetDownloadFolder() async { String folderPath = '/storage/emulated/0/documents/download folder'; Directory dir = Directory(folderPath); try { if (!await dir.exists()) { await dir.create(recursive: true); } return folderPath; } catch (e) { print("创建目录失败: $e"); throw Exception("无法创建下载目录"); } }
3. 验证AndroidManifest配置的正确性
确保你的targetSdkVersion设置为30或更高(对应Android 11),因为MANAGE_EXTERNAL_STORAGE权限仅在targetSdk 30+时生效。同时,权限声明要精准适配不同版本:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
4. 优化文件写入的细节处理
你的文件名中包含冒号:,虽然Android系统允许,但部分场景可能存在兼容问题,建议替换为下划线_避免潜在风险:
String dateNow = DateTime.now().toString().replaceAll(RegExp(r'[ :.]'), '_'); String randomName = dateNow + Utility.getRandomString(5); fullPath = "$dir/$randomName.pdf";
另外,写入文件时改用异步方法替代同步方法,既避免阻塞UI线程,也能更友好地捕获异常:
if (response.statusCode == 200) { try { File file = File(fullPath); await file.writeAsBytes(response.data); await showNotification(fullPath); } catch (e) { print("写入文件失败: $e"); Components.customSnackBar(context, "文件写入失败"); } }
内容的提问来源于stack exchange,提问作者Sasha
相关产品推荐
相关产品推荐

