文章目录
-
- 简述
- Android 配置
- Ios 配置
- 权限管理
- 避坑指南

简述
你提供的这套 Flutter 存储权限申请代码和配置,核心逻辑是对的,但缺少关键细节、异常处理、全场景适配(比如 Android 11/12 的特殊逻辑、iOS 细分权限、权限组申请等),我会补充完整的细节,让代码更健壮、适配所有主流系统版本(Android 10-14、iOS 11-17)。
一、补充 pubspec.yaml 依赖(完整)
除了 permission_handler,device_info_plus 是代码中依赖的(判断 Android 版本),需要一起添加,同时指定稳定版本:
dependencies:
flutter:
sdk: flutter
permission_handler: ^11.3.1 # 最新稳定版,修复了Android 14适配问题
device_info_plus: ^10.1.0 # 必须添加,用于判断Android SDK版本
path_provider: ^2.1.2 # 可选,配合权限获取文件路径(常用)
添加后执行:
flutter pub get
Android 配置
<!– 基础配置:适配所有Android版本 –>
<manifest …>
<!– 1. 兼容 Android 10 分区存储(可选,关闭Scoped Storage) –>
<!– 如果需要"访问所有文件",建议保留;仅访问媒体文件可删除 –>
<application
…
android:requestLegacyExternalStorage="true"> <!– Android 10 适配 –>
</application>
<!– 2. 媒体文件权限(基础,所有版本都加) –>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"/> <!– Android 10+ 自动失效 –>
<!– 3. 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"/>
<!– 4. Android 11+ 访问所有文件(仅当需要读写非媒体文件时添加) –>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
</manifest>
关键补充说明:
-
android:requestLegacyExternalStorage=“true”:仅对 Android 10(SDK 29)生效,关闭分区存储,兼容旧版权限逻辑;Android 11+ 需用 MANAGE_EXTERNAL_STORAGE。
-
WRITE_EXTERNAL_STORAGE 加 maxSdkVersion=“28”:避免 Android 10+ 重复申请(系统自动忽略)。
-
MANAGE_EXTERNAL_STORAGE 是特殊权限:无法通过 permission_handler 直接申请,必须引导用户到系统设置页开启(下面代码会补充)。
如果你的 build.gradle 中 targetSdkVersion = 34,需添加:
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"/>
Ios 配置
<dict>
<!– 相册读取(基础) –>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择图片/视频</string>
<!– 相册写入(iOS 11+) –>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要将图片/视频保存到相册</string>
<!– iOS 14+ 选择性相册权限(用户可只授权部分照片) –>
<key>NSPhotoLibraryLimitedUsageDescription</key>
<string>需要访问您选择的照片/视频</string>
<!– 本地文件访问(如Documents目录,iOS 11+) –>
<key>NSDocumentsFolderUsageDescription</key>
<string>需要访问本地文件以管理您的资料</string>
<!– 可选:如果需要访问iCloud文件 –>
<key>NSUbiquitousContainersUsageDescription</key>
<string>需要访问iCloud文件以同步您的资料</string>
</dict>
关键补充:
-
NSPhotoLibraryLimitedUsageDescription:iOS 14+ 新增,用户点击“选择照片”时显示,必须添加,否则权限申请会失败。
-
描述文案不能为空/太简单:App Store 审核会拒绝(比如不能只写“访问相册”,要说明用途)。
权限管理
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter/services.dart'; // 用于捕获平台异常
/// 申请存储/媒体权限(支持全平台、全版本)
/// [needAllFiles]:是否需要访问"所有文件"(仅Android 11+生效)
Future<bool> requestStoragePermission({bool needAllFiles = false}) async {
try {
// ========== 1. 区分平台和版本 ==========
if (Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
final sdkInt = androidInfo.version.sdkInt;
// Android 13+(SDK 33+):申请媒体细分权限
if (sdkInt >= 33) {
// 按需申请:比如只需要图片+视频,就申请这两个
final photoStatus = await Permission.photos.request();
final videoStatus = await Permission.videos.request();
final audioStatus = await Permission.audio.request();
// 只要需要的权限都授权,就返回true
return photoStatus.isGranted && videoStatus.isGranted && audioStatus.isGranted;
}
// Android 11-12(SDK 30-32):申请存储权限 + 可选"所有文件"
else if (sdkInt >= 30) {
// 先申请基础存储权限
final storageStatus = await Permission.storage.request();
if (!storageStatus.isGranted) return false;
// 如果需要访问所有文件,引导到设置页
if (needAllFiles) {
final hasManagePerm = await Permission.manageExternalStorage.isGranted;
if (!hasManagePerm) {
await openAppSettings(); // 跳转到系统设置页
// 再次检查权限
return await Permission.manageExternalStorage.isGranted;
}
}
return true;
}
// Android 10-(SDK 29-):传统存储权限
else {
final status = await Permission.storage.request();
return status.isGranted;
}
}
// ========== 2. iOS 适配 ==========
else if (Platform.isIOS) {
// iOS 14+ 区分"全部"和"所选",统一申请photos权限即可
final status = await Permission.photos.request();
if (status.isGranted || status.isLimited) { // Limited是iOS 14+的"所选照片"权限
return true;
} else if (status.isPermanentlyDenied) {
await openAppSettings(); // 引导到设置页
return await Permission.photos.isGranted;
}
return false;
}
// 其他平台(如Linux/Windows)默认返回true
return true;
} on PlatformException catch (e) {
// 捕获平台异常(比如权限插件未初始化)
print("申请权限失败:${e.message}");
return false;
} catch (e) {
print("申请权限异常:$e");
return false;
}
}
/// 快速检查存储权限是否已授权
Future<bool> checkStoragePermission({bool needAllFiles = false}) async {
if (Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
final sdkInt = androidInfo.version.sdkInt;
if (sdkInt >= 33) {
return await Permission.photos.isGranted &&
await Permission.videos.isGranted &&
await Permission.audio.isGranted;
} else if (sdkInt >= 30 && needAllFiles) {
return await Permission.manageExternalStorage.isGranted;
} else {
return await Permission.storage.isGranted;
}
} else if (Platform.isIOS) {
final status = await Permission.photos.status;
return status.isGranted || status.isLimited;
}
return true;
}
代码关键补充点:
异常捕获:添加 try-catch 捕获 PlatformException(插件调用异常),避免崩溃。
Android 11+ 所有文件权限:MANAGE_EXTERNAL_STORAGE 是特殊权限,必须引导用户到设置页开启,无法直接申请。
iOS 14+ 有限权限:处理 isLimited 状态(用户只授权部分照片),这是 iOS 14+ 新增的权限类型。
权限组申请:Android 13+ 拆分了媒体权限(照片/视频/音频),按需申请更合规。
工具方法:新增 checkStoragePermission,方便提前检查权限状态。
五、使用示例(完整流程)
// 点击按钮申请权限
void onTapRequestPermission() async {
// 1. 先检查权限
final hasPerm = await checkStoragePermission(needAllFiles: true);
if (hasPerm) {
print("权限已授权,可访问文件");
return;
}
// 2. 申请权限
final success = await requestStoragePermission(needAllFiles: true);
if (success) {
print("权限申请成功");
// 执行文件操作(如读取相册、读写文件)
} else {
print("权限申请失败,请手动开启");
}
}
避坑指南
-
Google Play 审核严格,仅允许文件管理器、备份类 App 使用该权限,普通 App 申请会被拒;
-
优先使用分区存储(Scoped Storage),仅在必要时申请该权限。
-
必须真实描述用途,不能夸大(比如“访问相册用于展示头像”,而不是“访问相册”);
-
缺少文案会导致 App 崩溃。
- 不要一启动 App 就申请,要在用户触发操作时(比如点击“选择照片”)再申请,提升授权率。
- 建议设置为 34(Android 14),并测试所有权限逻辑,避免版本兼容问题。
总结
配置层面:Android 需区分 SDK 版本添加权限,iOS 必须补充完整的权限描述文案;
代码层面:核心是处理 Android 13+ 媒体细分权限、Android 11+ 所有文件权限、iOS 14+ 有限相册权限;
体验层面:权限申请要在用户触发操作时进行,拒绝后引导到设置页,同时做好异常捕获。
这套补充后的代码和配置可以直接用于生产环境,覆盖所有主流系统版本和边界场景。
网硕互联帮助中心





评论前必须登录!
注册