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

如何用默认PDF应用打开GmsDocumentScanningResult.Pdf?

解决打开GmsDocumentScanningResult.Pdf时的FileUriExposedException问题

问题背景

尝试用默认PDF应用打开GmsDocumentScanningResult.Pdf对象时,抛出FileUriExposedException,错误信息:

file:///data/user/0/com.mypackage.docscanner/cache/mlkit_docscan_ui_client/9724995915195.pdf exposed beyond app through Intent.getData()

最初使用的代码:

resultIntent?.pdf?.let { pdf: GmsDocumentScanningResult.Pdf ->
    val pdfUri = pdf.uri
    val file = pdfUri.toFile()
    if (file.exists()) {
        val intent = Intent(Intent.ACTION_VIEW)
        intent.setDataAndType(file.toUri(), "application/pdf")
        try {
            startActivity(intent)
        } catch (e: FileUriExposedException) {
            
        }
    }
}

尝试配置FileProvider后仍崩溃,核心异常:

java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.hikarisource.docscanner/cache/mlkit_docscan_ui_client/1376275955600.pdf

错误原因

  1. 直接使用file://格式Uri分享应用私有目录文件,Android会触发FileUriExposedException,必须通过FileProvider生成content://格式的安全Uri
  2. 后续代码错误地将FileProvider生成的Uri转回File再调用toUri(),又回到了file://格式,同时路径配置未正确覆盖MLKit生成PDF的目录

正确解决方案

1. 确认AndroidManifest.xml的FileProvider配置

保持现有配置即可:

<application>
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>
</application>

2. 修正provider_paths.xml配置

确保覆盖MLKit生成PDF的缓存子目录,两种写法二选一:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!-- 方式1:仅指定MLKit的PDF存储目录 -->
    <cache-path
        name="mlkit_pdf_cache"
        path="mlkit_docscan_ui_client/" />
    
    <!-- 方式2:覆盖整个应用缓存目录(更通用) -->
    <!-- <cache-path name="cache" path="." /> -->
</paths>

3. 正确的打开代码

resultIntent?.pdf?.let { pdf: GmsDocumentScanningResult.Pdf ->
    val pdfFile = pdf.uri.toFile()
    if (pdfFile.exists()) {
        // 生成content://类型的安全Uri
        val contentUri = FileProvider.getUriForFile(
            applicationContext,
            "${applicationContext.packageName}.provider",
            pdfFile
        )

        val intent = Intent(Intent.ACTION_VIEW).apply {
            setDataAndType(contentUri, "application/pdf")
            // 授予目标应用临时读取权限
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        }

        // 检查是否有应用能处理该Intent,避免崩溃
        if (intent.resolveActivity(packageManager) != null) {
            startActivity(intent)
        }
    }
}

关键注意点

  • 禁止将FileProvider生成的content://Uri转回file://格式
  • 必须添加Intent.FLAG_GRANT_READ_URI_PERMISSION,确保第三方PDF应用能访问该文件
  • 调用resolveActivity检查,避免设备无PDF阅读器时触发崩溃

内容的提问来源于stack exchange,提问作者Leonardo Sibela

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:25:28