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

Android11打开PDF报ActivityNotFoundException及Firestore PDF下载适配分区存储问题

问题1:Android 11 打开PDF报ActivityNotFoundException的解决

直接原因是旧代码存在笔误:你为pdfIntent设置了数据和类型,但最终调用context.startActivity()时传入的是未初始化的intent变量,导致Intent参数无效。
完整修复步骤:

  1. 修正笔误,统一使用pdfIntent变量
  2. 启动前校验系统是否有支持打开PDF的应用,避免崩溃
  3. 确认FileProvider配置正确,res/xml/file_paths.xml需要包含对应路径的配置:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="external_files" path="Documents/" />
    <!-- 后续内部存储使用的话加这行 -->
    <files-path name="internal_files" path="." />
</paths>

修复后的旧方案打开方法:

suspend fun getPDFFileAndOpen(fileName: String) {
    val targetFileName = "$fileName.pdf"
    withContext(Dispatchers.IO) {
        val fileList = context.getExternalFilesDir(downloadDirectory)?.listFiles()
        val file = fileList?.find { it.name == targetFileName } ?: return@withContext
        val pdfUri = FileProvider.getUriForFile(context, authority, file)
        pdfIntent.setDataAndType(pdfUri, "application/pdf")
        // 校验是否有可处理的应用
        if (pdfIntent.resolveActivity(context.packageManager) != null) {
            context.startActivity(pdfIntent)
        } else {
            // 此处添加提示用户安装PDF阅读器的逻辑
        }
    }
}

问题2:不使用DownloadManager的完整实现方案

你代码中创建的File(context.filesDir, "$fileName.pdf")本身就是应用专属内部存储的持久化文件,不需要额外的保存步骤,下载完成后就已经永久存储在应用内部,除非用户卸载应用或者手动清除应用数据。
完整实现代码:

class PDFDownloaderWithoutManager(private val context: Context) {
    private val authority = "${BuildConfig.APPLICATION_ID}.fileprovider"

    suspend fun downloadPDF(uri: StorageReference, fileName: String) {
        withContext(Dispatchers.IO) {
            // 直接创建内部存储文件,下载完成即持久化保存
            val targetFile = File(context.filesDir, "$fileName.pdf")
            // 直接将Firestore文件下载到目标路径,不需要额外临时文件
            uri.getFile(targetFile).await()
            
            // 如果需要额外保存到公共下载目录对其他应用可见,可以调用下面的方法
            // saveToPublicDownload(targetFile, fileName)
        }
    }

    suspend fun getPDFFileAndOpen(fileName: String) {
        withContext(Dispatchers.IO) {
            val targetFile = File(context.filesDir, "$fileName.pdf")
            if (!targetFile.exists()) {
                // 处理文件不存在的逻辑
                return@withContext
            }
            val pdfUri = FileProvider.getUriForFile(context, authority, targetFile)
            val pdfIntent = Intent(Intent.ACTION_VIEW).apply {
                setDataAndType(pdfUri, "application/pdf")
                flags = Intent.FLAG_ACTIVITY_NEW_TASK
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }
            if (pdfIntent.resolveActivity(context.packageManager) != null) {
                context.startActivity(pdfIntent)
            } else {
                // 提示用户安装PDF阅读器
            }
        }
    }

    // 可选:保存到公共下载目录,适配分区存储,不需要申请存储权限
    private fun saveToPublicDownload(sourceFile: File, fileName: String) {
        val contentValues = ContentValues().apply {
            put(MediaStore.Downloads.DISPLAY_NAME, "$fileName.pdf")
            put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                put(MediaStore.Downloads.IS_PENDING, 1)
            }
        }
        val resolver = context.contentResolver
        val targetUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) ?: return
        resolver.openOutputStream(targetUri)?.use { outputStream ->
            sourceFile.inputStream().use { inputStream ->
                inputStream.copyTo(outputStream)
            }
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            contentValues.clear()
            contentValues.put(MediaStore.Downloads.IS_PENDING, 0)
            resolver.update(targetUri, contentValues, null, null)
        }
    }
}

关于uri.getFile("URI TO SAVE FILE TO")方法的说明:这个方法接收的是本地文件的Uri,如果你要直接下载到MediaStore提供的公共目录Uri,可以直接传入上面saveToPublicDownload方法中创建的targetUri,不需要先创建内部存储的文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:54:03