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

Android R下载Base64编码PDF并调用预装查看器打开的问题求解

解决方案

你需要的无文件选择器、直接打开PDF的需求可以通过FileProvider实现,完美适配Android R及以上版本,具体操作步骤如下:

步骤1:配置FileProvider

在模块级AndroidManifest.xml的<application>节点中添加如下配置:

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

步骤2:创建文件路径配置文件

在res/xml目录下新建file_paths.xml文件,内容如下(对应你存储PDF的外部应用私有下载目录):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path
        name="app_downloads"
        path="Download/" />
</paths>

步骤3:修改原有逻辑代码

你第一版的代码只需调整2处即可正常运行:

  1. 文件名补.pdf后缀,保证系统能识别文件格式
  2. 替换Uri.fromFile为FileProvider生成的Content Uri,同时给外部PDF查看器授予临时读取权限

修改后的完整代码如下:

lifecycleScope.launch {
    withContext(Dispatchers.IO) {
        try {
            Snackbar.make(binding.root, getString(R.string.load_document_started), Snackbar.LENGTH_LONG).show()
            
            val documentData = DocumentDao().get(document.id, montageOrder)
            val docAsByte = Base64.decode(documentData.data, Base64.DEFAULT)

            val currentDateString  = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())

            // 补全.pdf后缀
            val fileName = document.documentType
                .lowercase()
                .replace("ä", "ae")
                .replace("ü", "ue")
                .replace("ö", "oe") +
                    "_" + currentDateString + ".pdf"

            val file = File(requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName)
            val fileStream = FileOutputStream(file)
            fileStream.write(docAsByte)
            fileStream.close()

            val context = requireContext()
            val target = Intent(Intent.ACTION_VIEW)
            // 用FileProvider生成Content Uri,authorities需和manifest配置一致
            val pdfUri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
            target.setDataAndType(pdfUri, "application/pdf")
            // 授予外部应用临时读取权限
            target.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            target.flags = Intent.FLAG_ACTIVITY_NO_HISTORY

            val intent = Intent.createChooser(target, "打开PDF")
            startActivity(intent)

        } catch (e: Exception) {
            Log.e(TAG, "Dokument konnte nicht geladen werden: " + e.message, e)
            Snackbar.make(binding.root, getString(R.string.exception_could_not_load_document), Snackbar.LENGTH_LONG).show()
        }
    }
}

原有方案问题说明

  • 第一版代码抛出FileUriExposedException是因为Android 7.0及以上版本禁止应用直接向外部暴露file://类型的Uri,必须使用content://类型的Uri共享文件
  • 第二版SAF方案的CreatePdfDocument合约本身就会触发系统文件选择器,不符合无弹窗需求,且打开文件时未授予读取权限导致无法直接打开

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:18:01