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

Flutter媒体下载应用真机存储权限异常问题求助

Flutter媒体下载应用真机无法请求存储权限且下载失败问题解决(compileSdkVersion 33)

核心问题分析

  1. Android 13(API33)权限机制变更:原READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限在API33已被废弃,转而使用针对不同媒体类型的细分权限,当前使用的Permission.storage在API33真机上不会触发权限请求弹窗。
  2. 权限请求逻辑无等待:download方法调用checkPermission()时未用await,导致下载逻辑在权限请求完成前就执行,直接触发存储访问失败。
  3. 硬编码存储路径兼容性差:直接使用/storage/emulated/0/Download/路径在部分真机上可能因权限或路径结构差异导致写入失败。

具体修复步骤

1. 更新AndroidManifest权限配置

针对API33及以上版本添加媒体文件访问权限,保留低版本兼容配置:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 基础权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <!-- 低版本(<33)存储权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    
    <!-- API33+ 媒体权限(对应音频文件) -->
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

    <!-- 仅需批量管理文件时保留,否则可移除 -->
    <uses-permission
        android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        android:minSdkVersion="30" />

    <application
        android:label="downloader"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher"
        android:usesCleartextTraffic="true"
        android:requestLegacyExternalStorage="true">
        <!-- 原有application内容不变 -->
    </application>
</manifest>

2. 修正权限请求与下载逻辑

  • 适配API33+权限,使用对应媒体权限而非Permission.storage
  • 确保下载逻辑等待权限请求完成
  • 处理权限拒绝边界情况,避免无限递归
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:path_provider/path_provider.dart';

// 检查权限方法
Future<bool> checkPermission() async {
  bool hasPermission = false;
  if (Platform.isAndroid) {
    final androidInfo = await DeviceInfoPlugin().androidInfo;
    if (androidInfo.version.sdkInt >= 33) {
      // API33+ 请求音频读取权限
      var audioStatus = await Permission.readMediaAudio.status;
      if (!audioStatus.isGranted) {
        audioStatus = await Permission.readMediaAudio.request();
      }
      hasPermission = audioStatus.isGranted;
    } else {
      // 低版本请求存储权限
      var storageStatus = await Permission.storage.status;
      if (!storageStatus.isGranted) {
        storageStatus = await Permission.storage.request();
      }
      hasPermission = storageStatus.isGranted;
    }
  } else {
    // iOS等其他平台默认授权
    hasPermission = true;
  }

  hasPermission ? print('权限已授予') : print('权限被拒绝');
  return hasPermission;
}

// 下载方法修正
Future<void> download(String name, String link) async {
  bool permissionGranted = await checkPermission();
  if (!permissionGranted) {
    print('权限未授予,无法下载');
    // 可添加弹窗提示用户手动开启权限
    return;
  }

  NotificationService().showNotification(id: 0, title: '下载已开始');
  try {
    var response = await http.get(Uri.parse(link));
    // 获取系统公共下载目录
    Directory? downloadDir = await getExternalStoragePublicDirectory(DirectoryDownloads);
    if (downloadDir == null) {
      print('无法获取公共下载目录');
      return;
    }
    final file = File('${downloadDir.path}/$name.m4a');
    await file.writeAsBytes(response.bodyBytes);
    
    NotificationService().showNotification(
        id: 1, title: '下载完成', body: '$name 下载成功');
    MediaScanner.loadMedia(path: file.path);
    print('下载完成');
  } catch (e) {
    print('下载错误: $e');
    NotificationService().showNotification(
        id: 2, title: '下载失败', body: '$name 下载出错');
  }
}

3. 补充必要依赖

在pubspec.yaml中添加对应依赖:

dependencies:
  flutter:
    sdk: flutter
  permission_handler: ^10.2.0
  device_info_plus: ^9.0.0
  path_provider: ^2.0.15
  http: ^0.13.5

额外注意事项

  • 若无需访问应用外媒体文件,可使用应用专属存储目录(无需权限),路径可通过getApplicationDocumentsDirectory()获取。
  • MANAGE_EXTERNAL_STORAGE为特殊权限,仅当应用需批量管理所有文件时使用,提交Google Play需说明用途,否则可能被拒。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:55:21