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

Android 30及以上版本如何通过MediaQuery搜索PDF文件?

Android 10+ 访问沙箱外PDF文件的解决方案

1. 权限修正

你当前使用的READ_MEDIA_IMAGES仅授权访问图片、视频类媒体资源,无法读取PDF这类文档文件,需根据系统版本适配权限:

  • Android 13+(API33及以上):在Manifest中添加READ_MEDIA_DOCUMENTS权限,动态申请该权限
  • Android 10-12(API29-32):依赖READ_EXTERNAL_STORAGE权限,同样需要动态申请

Manifest权限声明示例:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_DOCUMENTS"
    android:minSdkVersion="33" />

2. 修复MediaStore查询逻辑

问题点说明

  • API29+限制直接通过DATA列获取文件路径,强制使用Content Uri访问文件,避免路径失效或权限问题
  • 需确保查询逻辑匹配标准PDF的MIME类型(application/pdf)

修改后的代码示例

private fun getPdfList(): ArrayList<Uri>? {
    val pdfList = ArrayList<Uri>()
    val projection = arrayOf(
        MediaStore.Files.FileColumns._ID,
        MediaStore.Files.FileColumns.DISPLAY_NAME,
        MediaStore.Files.FileColumns.MIME_TYPE
    )
    val sortOrder = "${MediaStore.Files.FileColumns.DATE_ADDED} DESC"

    val selection = "${MediaStore.Files.FileColumns.MIME_TYPE} = ?"
    val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf") ?: "application/pdf"
    val selectionArgs = arrayOf(mimeType)

    val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
    } else {
        MediaStore.Files.getContentUri("external")
    }

    // 按系统版本检查对应权限
    val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_DOCUMENTS) == PackageManager.PERMISSION_GRANTED
    } else {
        ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
    }

    if (hasPermission) {
        contentResolver.query(collection, projection, selection, selectionArgs, sortOrder)?.use { cursor ->
            val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)
            val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME)

            while (cursor.moveToNext()) {
                val id = cursor.getLong(idColumn)
                val fileName = cursor.getString(nameColumn)
                val contentUri = ContentUris.withAppendedId(collection, id)
                pdfList.add(contentUri)
                Log.e("TAG", "PDF File Name: $fileName, Uri: $contentUri")
            }
        }
    } else {
        // 触发权限申请
        requestRequiredPermissions()
    }
    return pdfList
}

// 权限申请方法示例
private fun requestRequiredPermissions() {
    val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        arrayOf(Manifest.permission.READ_MEDIA_DOCUMENTS)
    } else {
        arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
    }
    ActivityCompat.requestPermissions(this, permissions, 1001)
}

3. 替代方案:存储访问框架(SAF)

SAF并非仅Android 10可用,API19及以上即可使用,是Scoped Storage推荐的文件访问方式:

  • 调用SAF让用户选择单个PDF文件或整个文件夹,无需特殊权限即可访问选中内容
  • 可通过ACTION_OPEN_DOCUMENT或ACTION_OPEN_DOCUMENT_TREE发起选择,获取的Uri可通过takePersistableUriPermission长期保存

示例代码(选择单个PDF):

private fun pickPdf() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/pdf"
    }
    startActivityForResult(intent, 1002)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 1002 && resultCode == Activity.RESULT_OK) {
        data?.data?.let { uri ->
            // 获取持久化权限
            contentResolver.takePersistableUriPermission(
                uri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION
            )
            // 使用uri访问PDF文件
            Log.e("TAG", "Selected PDF Uri: $uri")
        }
    }
}

额外注意事项

  • 若下载的PDF未被MediaStore索引,可通过MediaScannerConnection触发媒体扫描,确保文件被收录
  • API29+禁止直接操作沙箱外的文件路径,所有文件操作需通过Content Uri或SAF进行

内容的提问来源于stack exchange,提问作者Sunil Chaudhary

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 12:23:24