Android 13设备Download目录PDF文件读取权限问题(Kotlin开发)
Android 13读取Download目录PDF文件权限解决方案
一、权限声明与动态申请
Manifest权限配置
针对Android 13(API 33+),在AndroidManifest.xml中添加对应权限:<!-- 兼容Android 12及以下的外部存储读取权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+媒体文件权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- Android 13+访问非媒体文档(如PDF)需保留此权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />Kotlin动态申请权限
根据系统版本判断并申请权限:private const val PERMISSION_REQUEST_CODE = 1001 fun requestStoragePermissions(context: Context) { val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { arrayOf( Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE ) } else { arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE) } if (ContextCompat.checkSelfPermission(context, permissions.first()) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(context as Activity, permissions, PERMISSION_REQUEST_CODE) } }
二、推荐:使用存储访问框架(SAF)读取单个PDF
Android 13+官方推荐用SAF访问单个文件,无需申请外部存储权限,流程如下:
- 启动PDF选择器
private const val DOCUMENT_REQUEST_CODE = 1002 fun openPDFPicker(activity: Activity) { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "application/pdf" // 指定仅选择PDF文件 } activity.startActivityForResult(intent, DOCUMENT_REQUEST_CODE) } - 处理返回的URI并读取
注:若使用Jetpack的Activity Result API,替换override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == DOCUMENT_REQUEST_CODE && resultCode == RESULT_OK) { data?.data?.let { pdfUri -> // 申请永久访问权限 contentResolver.takePersistableUriPermission( pdfUri, Intent.FLAG_GRANT_READ_URI_PERMISSION ) // 读取文件内容 contentResolver.openInputStream(pdfUri)?.use { inputStream -> // 在这里处理PDF输入流,比如解析或复制 } } } }onActivityResult为对应的回调即可。
三、批量访问PDF:申请MANAGE_EXTERNAL_STORAGE权限
如果需要批量遍历Download目录下的所有PDF,需申请特殊权限MANAGE_EXTERNAL_STORAGE:
- Manifest声明
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> - 引导用户开启权限
注意:该权限仅适用于必须批量访问文件的场景,Google Play审核会严格限制其使用。fun requestManageStoragePermission(activity: Activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply { data = Uri.parse("package:${activity.packageName}") } activity.startActivity(intent) } } }
四、排查要点
- 用
contentResolver.checkUriPermission(pdfUri, android.os.Process.myPid(), android.os.Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION)验证URI权限是否有效。 - 确认目标PDF文件存在于
/storage/emulated/0/Download目录下,避免路径错误。 - Android 13中禁止直接通过
File类访问公共目录的文件,优先用ContentResolver或SAF。
内容的提问来源于stack exchange,提问作者M.Omer
相关产品推荐
相关产品推荐

