Flutter创建外部存储文件夹报Operation not permitted权限错误
问题原因
报错核心是Android高版本存储权限规则变更:
- Android 10(API 29)开始强制启用分区存储,普通应用默认只能访问自己的专属存储目录和授权的公共媒体目录
- Android 11(API 30)及以上版本完全废弃了
WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE的根目录读写能力,仅靠这两个权限根本无法直接在storage/emulated/0/根目录创建文件/文件夹
另外你的代码本身还有三个逻辑缺陷:
- 调用权限申请方法后没有二次校验授权结果,用户拒绝权限后代码还是会继续执行创建文件夹的逻辑
- 硬编码存储根目录路径,不同厂商、不同系统版本的外部存储路径不一定是
storage/emulated/0/ - 调用
path.create()时没加recursive: true参数,只要上级目录不存在就会直接抛创建失败的错误
修复方案
1. 修改AndroidManifest.xml配置
在原有权限声明下补充高版本需要的权限,同时给application标签添加Android 10兼容属性:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cameraapp"> <!-- 原有权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 新增Android11+需要的所有文件访问权限 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <application android:label="cameraapp" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" <!-- 新增这行,兼容Android10分区存储过渡规则 --> android:requestLegacyExternalStorage="true"> <!-- 其余activity等配置保持原样即可 --> </application> </manifest>
2. 修正Dart层逻辑
不要硬编码路径,按系统版本分支申请对应权限,申请后必须校验结果再执行文件操作,修正后的代码如下:
import 'dart:io'; import 'package:permission_handler/permission_handler.dart'; import 'package:path_provider/path_provider.dart'; Future<String> createTargetFolder() async { const folderName = "newcreatefoldr"; if (Platform.isAndroid) { PermissionStatus storageStatus; // Android11及以上版本申请管理所有文件权限 if (int.parse(Platform.version.split('.')[0]) >= 11) { storageStatus = await Permission.manageExternalStorage.status; if (!storageStatus.isGranted) { storageStatus = await Permission.manageExternalStorage.request(); } } else { // Android10及以下用旧存储权限 storageStatus = await Permission.storage.status; if (!storageStatus.isGranted) { storageStatus = await Permission.storage.request(); } } // 权限未授予直接终止流程 if (!storageStatus.isGranted) { throw FileSystemException("存储权限未授予,无法创建文件夹"); } } // 通过官方插件获取外部存储路径,不要硬编码 final Directory? externalRoot = await getExternalStorageDirectory(); if (externalRoot == null) { throw FileSystemException("无法获取设备外部存储路径"); } final Directory targetDir = Directory("${externalRoot.path}/$folderName"); if (!await targetDir.exists()) { // recursive设为true会自动创建缺失的上级目录 await targetDir.create(recursive: true); } return targetDir.path; }
3. 额外说明
- 如果你的应用不需要在存储根目录创建文件夹,只是存应用自己的文件,完全可以不用申请任何存储权限,直接调用
getApplicationDocumentsDirectory()或者getExternalStorageDirectory()拿到应用专属目录操作即可,不会有权限问题 - 若需要上架Google Play,使用
MANAGE_EXTERNAL_STORAGE权限必须在审核时明确说明使用场景,仅当应用是文件管理器、备份工具这类确实需要访问全存储的场景才能通过审核,普通应用用这个权限会被直接拒审
内容的提问来源于stack exchange,提问作者Khaled Mortaja
相关产品推荐
相关产品推荐

