Android 11应用内PDF下载与预览功能权限异常问题求助
你碰到的这个问题,本质是Android 11(API 30)引入的分区存储机制在限制文件访问——哪怕你用了应用的外部缓存目录(externalCacheDir),直接用file:// Uri把文件分享给PDF查看器也会被系统拦截,因为第三方应用没有权限访问你的应用私有目录。下面是一步步的解决方案:
核心问题拆解
Android 11启用分区存储后,READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限的作用范围被大幅缩小,而且其他应用无法通过file:// Uri直接访问你的应用私有文件(包括externalCacheDir里的文件),这就是你看到EACCES (Permission denied)错误的根本原因。
解决方案:用FileProvider安全分享文件
FileProvider是Android官方提供的内容提供者,能安全地把你的应用私有文件授权给其他应用访问,具体步骤如下:
1. 在AndroidManifest中注册FileProvider
在<application>标签内添加以下配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
⚠️ 注意:authorities必须用你的应用包名加上.fileprovider,保证唯一性,比如你的包名是com.example.myapp,那这里就填com.example.myapp.fileprovider。
2. 创建file_paths.xml资源文件
在res/xml/目录下新建file_paths.xml(如果xml目录不存在就手动创建),内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 配置允许分享应用外部缓存目录下的所有文件 --> <external-cache-path name="external_cache" path="." /> </paths>
这个文件告诉FileProvider,你要分享的文件位于应用的外部缓存目录。
3. 修改代码中的Intent逻辑
把原来生成file:// Uri的代码替换成FileProvider生成的Content Uri,同时给Intent添加临时读取权限:
val int = Intent(Intent.ACTION_VIEW).apply { // 用FileProvider生成合法的Content Uri val contentUri = FileProvider.getUriForFile( a, "${app.packageName}.fileprovider", // 和Manifest里的authorities保持一致 r ) setDataAndType(contentUri, "application/pdf") // 授予PDF查看器临时读取该文件的权限 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } startActivityForResult(int, 1)
4. 优化权限声明(可选)
因为你用的是应用私有目录(externalCacheDir),实际上在Android 10+系统中不需要申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限。如果你的targetSdkVersion是30+,可以给这两个权限加上maxSdkVersion,避免不必要的权限申请:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
额外提醒
- 确保你的项目使用AndroidX库,这样才能正常引用
androidx.core.content.FileProvider;如果还用旧的Support库,就换成android.support.v4.content.FileProvider。 - 大部分主流PDF查看器(比如Google PDF Viewer)都支持通过Content Uri访问文件,测试时可以优先用这些应用验证。
这样修改后,Android 11设备上就能正常打开下载的PDF文件了,同时也符合Android最新的存储规范。
内容的提问来源于stack exchange,提问作者Martin




