如何用默认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
错误原因
- 直接使用
file://格式Uri分享应用私有目录文件,Android会触发FileUriExposedException,必须通过FileProvider生成content://格式的安全Uri - 后续代码错误地将
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
相关产品推荐
相关产品推荐

