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

Android 11 将外部存储PDF复制到内部存储出现EACCES权限错误如何解决

Android 11 外部存储PDF访问权限报错解决方案

问题原因

Android 10 可通过requestLegacyExternalStorage兼容原始路径访问逻辑,所以你的代码运行正常。Android 11 强制执行分区存储规则,直接访问公共目录的原始文件路径会被系统禁止:

  1. READ_EXTERNAL_STORAGE权限在Android 11及以上仅能访问媒体类文件(图片、音视频),无法访问PDF等非媒体文件
  2. 你代码中硬编码/sdcard/Documents/PDFConverter/my_file.pdf路径构造File对象的方式,在Android 11上没有访问权限,所以触发EACCES权限拒绝报错

具体修复步骤

步骤1:调整AndroidManifest.xml权限配置

<!-- 原有权限保留,限制仅低版本生效 -->
<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />
<uses-permission
    android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="29" />
<!-- 仅文件管理、PDF批量处理类工具可添加以下权限,普通应用添加会导致谷歌Play上架被拒 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    android:minSdkVersion="30" />

步骤2:选择适配的文件访问方案(二选一,优先选方案1)

方案1:使用存储访问框架(SAF)获取文件(无审核风险,全版本适配)

不要硬编码外部存储路径,调用系统文件选择器让用户主动选择PDF文件,拿到的Uri自带临时访问权限,不需要FileProvider即可直接读取:

// Fragment中添加文件选择逻辑
private val PICK_PDF_REQUEST = 1001

// 调起系统PDF选择器
fun pickPDFFile() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/pdf"
    }
    startActivityForResult(intent, PICK_PDF_REQUEST)
}

// 接收选择结果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == PICK_PDF_REQUEST && resultCode == Activity.RESULT_OK) {
        data?.data?.let { pdfUri ->
            // 直接使用用户选择的Uri调用复制逻辑即可
            ScopeStoreUtils.copyFileIntoFilesDir(requireContext(), pdfUri)
        }
    }
}

方案2:申请全量存储访问权限(仅适合必须批量扫描公共目录文件的应用)

如果你的应用确实需要批量读取公共目录下的所有PDF,无法让用户手动选择,可申请特殊权限:

// Android 11+ 权限校验逻辑
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    if (!Environment.isExternalStorageManager()) {
        // 跳转系统设置页,引导用户开启所有文件访问权限
        val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
        startActivity(intent)
    } else {
        // 权限已获取,可直接读取公共目录文件
    }
}

步骤3:修复代码调用错误

你现有Fragment代码中调用的方法是ScopeStoreUtils.copyFileIntoFiles(context, contentUri),但工具类中定义的方法名为copyFileIntoFilesDir,名称不匹配会导致调用异常,需要统一方法名。


内容的提问来源于stack exchange,提问作者Ahmet B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 20:15:01