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

Flutter保存PDF触发PathAccessException权限拒绝问题求助

解决Flutter保存PDF到外部存储的权限拒绝问题

问题根源

你的错误是因为Android 13(API 33+)废弃了传统的WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE权限,常规的Permission.storage请求在Android 13+仅授予媒体文件的读取权限,无法写入到用户选择的任意公共目录。

解决方案

1. 更新AndroidManifest.xml权限配置

在android/app/src/main/AndroidManifest.xml中添加兼容新旧版本的权限:

<!-- 兼容Android 12及以下版本 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<!-- Android 13+ 所需的全存储管理权限 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

2. 添加设备信息依赖

需要获取Android SDK版本来判断权限类型,在pubspec.yaml中添加:

dependencies:
  device_info_plus: ^9.1.0 # 使用最新稳定版本

执行flutter pub get安装依赖。

3. 修改权限请求与保存逻辑

替换原按钮点击事件中的权限处理代码,根据Android版本请求对应权限:

onButtonPressed: () async {
  final pdf = pw.Document();
  final font = await rootBundle.load("assets/Roboto/Roboto-Black.ttf");
  final ttf = pw.Font.ttf(font);
  pdf.addPage(pw.Page(
    pageFormat: PdfPageFormat.a4,
    build: (pw.Context context) {
      return pw.Center(
        child: pw.Text('Dart is awesome',
            style: pw.TextStyle(font: ttf, fontSize: 40)),
      );
    },
  ));

  bool hasPermission = false;
  if (Platform.isAndroid) {
    final androidInfo = await DeviceInfoPlugin().androidInfo;
    if (androidInfo.version.sdkInt >= 33) {
      // Android 13+ 请求全存储管理权限
      final status = await Permission.manageExternalStorage.request();
      if (status.isGranted) {
        hasPermission = true;
      } else if (status.isDenied || status.isPermanentlyDenied) {
        // 引导用户到应用设置手动开启权限
        await openAppSettings();
        return;
      }
    } else {
      // Android 12及以下请求传统存储权限
      final status = await Permission.storage.request();
      hasPermission = status.isGranted;
    }
  } else {
    // 其他平台直接请求存储权限
    final status = await Permission.storage.request();
    hasPermission = status.isGranted;
  }

  if (hasPermission) {
    final directoryPath = await FilePicker.platform.getDirectoryPath();
    if (directoryPath != null) {
      final filePath = path.join(directoryPath, 'example.pdf');
      final file = File(filePath);
      await file.writeAsBytes(await pdf.save());
      print('PDF saved to $filePath');
    } else {
      print('No folder selected');
    }
  } else {
    print('Permission denied');
  }
},

替代方案:无需全存储权限的固定目录保存

如果不需要用户选择任意文件夹,仅需保存到系统默认的Downloads目录,可以使用path_provider包,无需申请MANAGE_EXTERNAL_STORAGE权限:

  1. 添加依赖:
dependencies:
  path_provider: ^2.1.1
  1. 修改保存逻辑:
if (hasPermission) {
  final downloadsDir = await getDownloadsDirectory();
  if (downloadsDir != null) {
    final filePath = path.join(downloadsDir.path, 'example.pdf');
    final file = File(filePath);
    await file.writeAsBytes(await pdf.save());
    print('PDF saved to $filePath');
  }
}

注意事项

  • MANAGE_EXTERNAL_STORAGE权限属于特殊权限,Google Play可能会对使用该权限的应用进行审核,仅当应用确实需要访问任意文件目录时才使用。
  • 测试时需卸载旧版本应用后重新安装,否则权限配置可能不生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 21:00:35