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

Android 13设备Download目录PDF文件读取权限问题(Kotlin开发)

Android 13读取Download目录PDF文件权限解决方案

一、权限声明与动态申请

  1. 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" />
    
  2. 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访问单个文件,无需申请外部存储权限,流程如下:

  1. 启动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)
    }
    
  2. 处理返回的URI并读取
    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输入流,比如解析或复制
                }
            }
        }
    }
    
    注:若使用Jetpack的Activity Result API,替换onActivityResult为对应的回调即可。

三、批量访问PDF:申请MANAGE_EXTERNAL_STORAGE权限

如果需要批量遍历Download目录下的所有PDF,需申请特殊权限MANAGE_EXTERNAL_STORAGE:

  1. Manifest声明
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    
  2. 引导用户开启权限
    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)
            }
        }
    }
    
    注意:该权限仅适用于必须批量访问文件的场景,Google Play审核会严格限制其使用。

四、排查要点

  • 用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:52:18