You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Android 13(SDK33)存储权限申请失败问题求助

解决Android 13(SDK33)Flutter存储权限与目录创建失败问题

一、权限问题根源与修正

Android 13(SDK33)彻底移除了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE的用户授权入口,拆分出READ_MEDIA_IMAGES、READ_MEDIA_AUDIO、READ_MEDIA_VIDEO三个细分媒体权限。Permission.storage在SDK33+环境下完全失效,所以调用后永远返回false。

你的场景是处理录音文件,SDK33+应申请Permission.audio(对应系统的READ_MEDIA_AUDIO权限)而非Permission.photos。修正后的权限申请代码:

bool permissionGranted = false;

if (Platform.isAndroid) {
  final androidInfo = await DeviceInfoPlugin().androidInfo;
  if (androidInfo.version.sdkInt <= 32) {
    Map<Permission, PermissionStatus> permissions = await [
      Permission.storage,
      Permission.microphone,
    ].request();
    permissionGranted = permissions[Permission.storage]!.isGranted &&
        permissions[Permission.microphone]!.isGranted;
  } else {
    Map<Permission, PermissionStatus> permissions = await [
      Permission.audio, // 替换为音频权限,匹配录音文件场景
      Permission.microphone,
    ].request();
    permissionGranted = permissions[Permission.audio]!.isGranted &&
        permissions[Permission.microphone]!.isGranted;
  }
}

二、目录创建失败的核心原因

/storage/recordings属于外部存储公共根目录,从Android 10(API29)开始,分区存储机制限制APP直接访问该路径,即便授予媒体权限也无法创建目录。requestLegacyExternalStorage="true"仅在API29-30版本生效,SDK33+完全失效。

两种可行的目录方案:

方案1:应用专属外部存储目录(推荐,无需额外权限)

该目录属于APP私有空间,卸载时自动删除,无需申请媒体权限:

// 需要先添加path_provider依赖:path_provider: ^2.0.15(或最新版本)
Directory directory = Directory('${(await getExternalStorageDirectory())!.path}/Recordings');
await directory.create(recursive: true);

路径示例:Android/data/com.example.keyword_speech/files/Recordings

方案2:公共媒体目录(适合需要用户在系统文件管理器可见的场景)

如果要将录音放在公共音频目录下:

Directory directory = Directory('${(await getExternalStorageDirectory())!.parent.parent.parent}/Music/Recordings');
await directory.create(recursive: true);

路径示例:/storage/emulated/0/Music/Recordings,需确保已授予Permission.audio权限。

三、AndroidManifest.xml清理优化

移除冗余权限,避免系统权限映射混淆:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.keyword_speech">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <!-- 仅对SDK32及以下保留存储权限,SDK33+自动忽略 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>

    <!-- SDK33+音频媒体权限 -->
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

    <!-- 非文件管理器类应用不要使用该权限,谷歌审核会拒绝 -->
    <!-- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> -->

    <application ... android:requestLegacyExternalStorage="true">
    ...
    </application>
</manifest>

四、额外注意事项

  • MANAGE_EXTERNAL_STORAGE权限仅对文件管理器、备份工具等特定类型应用开放,普通应用申请会被谷歌Play审核拒绝,尽量避免使用。
  • 若必须访问公共根目录,需通过openAppSettings()跳转应用设置页面,引导用户手动开启“所有文件访问权限”,但此方式不推荐。

内容的提问来源于stack exchange,提问作者jadekim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 17:32:12