android.content.ActivityNotFoundException:在 android 11 打开 pdf 时未发现 Activity 处理 Intent

android.content.ActivityNotFoundException: No Activity found to handle Intent when opening pdf at android 11

我知道有很多类似的主题,但它们要么已经过时,要么不适用于 pdf。

我的问题是,如何从 Cloud firestore 下载 pdf 并将其保存到内部存储器中?我通常的方法是使用 downloadmanager 并将 pdf 保存到外部存储中,但是由于分区存储,这不再有效,我需要找到一种新方法。

目前,我只知道如何创建一个临时文件,以及如何从firestore下载pdf到这个临时文件中,但不知道如何保存。

旧方法(使用下载管理器)

class PDFDownloader(private val context: Context) {
    private val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager

    private val downloadDirectory = Environment.DIRECTORY_DOCUMENTS

    private val authority = "${BuildConfig.APPLICATION_ID}.fileprovider"

    private val pdfIntent = Intent(Intent.ACTION_VIEW).apply {
       flags = Intent.FLAG_ACTIVITY_NEW_TASK
       addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }


    // DOWNLOADING THE PDF INTO EXTERNAL STORAGE
    suspend fun downloadPDF(pdfUri: String, fileName: String) {
       val pdfUrl = Firebase.storage.getReferenceFromUrl(pdfUri).downloadUrl.await()

       // NOT WORKING ANYMORE BECAUSE OF SCOPED STORAGE
       val request = DownloadManager.Request(pdfUrl)
           .setTitle(fileName)
           .setDestinationInExternalFilesDir(context, downloadDirectory, "$fileName.pdf")

       downloadManager.enqueue(request)
    }


    // RETRIEVING THE PDF FROM EXTERNAL STORAGE
    suspend fun getPDFFileAndOpen(fileName: String) {
       val regex = "$fileName.pdf"

       withContext(Dispatchers.IO) {
          val fileList = context.getExternalFilesDir(downloadDirectory)?.listFiles()
          val file = fileList?.find { it.name == regex }

          pdfIntent.setDataAndType(FileProvider.getUriForFile(context, authority, file), "application/pdf")

          context.startActivity(intent)
       }
   }
}

新方法(没有下载管理器)

class PDFDownloaderWithoutManager(private val context: Context) {

   override suspend fun downloadPDF(uri: StorageReference, fileName: String) {
        withContext(Dispatchers.IO) {
            // Step 1: Creating a temporary file
            val tempFile =  File(context.filesDir, "$fileName.pdf")

            // Step 2: Downloading the pdf from cloud-firestore into tempFile
            uri.getFile(tempFile).await()

            // Step 3: Saving the file into internal storage
            // OR SAVING INTO EXTERNAL STORAGE WITH SCOPED STORAGE 
            // (I take whats easier)
            ?????????????????????????????????????????????????????
        }
    }
}

   // RETRIEVING THE PDF FROM INTERNAL STORAGE
    suspend fun getPDFFileAndOpen(fileName: String) {
       val regex = "$fileName.pdf"
       
       ????????????????????????????????????????????????????????????
   }

还有一个方法uri.getFile("URI TO SAVE FILE TO),但是我也不知道怎么用

编辑

使用下载管理器按预期工作,它成功地从 firestore 下载文件 (yay)。我遇到的唯一问题是,我无法再在 android 11 打开 pdf。我收到以下错误:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=content://com.example.app.fileprovider/external_files/Documents/Kalibrierung und Überprüfung.pdf typ=application/pdf flg=0x10000001 }
        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2067)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1727)
        at android.app.ContextImpl.startActivity(ContextImpl.java:1023)
        at android.app.ContextImpl.startActivity(ContextImpl.java:994)
        at android.content.ContextWrapper.startActivity(ContextWrapper.java:403)
        at com.example.app.business.domain.validator.document.FileLegacyValidator.openPdf(FileLegacyValidator.kt:38)
        at com.example.app.business.domain.validator.document.FileLegacyValidator.openPDFFileOrNull(FileLegacyValidator.kt:35)
        at com.example.app.presentation.documents.DocumentViewModel$setStateEvent.invokeSuspend(DocumentViewModel.kt:36)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

这不起作用:context.startActivity(intent)

编辑:在您最近对问题进行编辑后回答不相关。

如果您要使用外部存储,请按以下步骤操作:

val isExternalStorageWritable =
    (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)
if (!isExternalStorageWritable ) {
    // handle error: Storage not available
    return
}

val rootFolder = context.getExternalFilesDir(null)
val downloadsFolder = File(rootFolder, "downloads")
val isDownloadsFolderCreated = downloadsFolder.mkdirs()
if (!isDownloadsFolderCreated) {
    // handle error: unable to create folder
    return
}

val tempInputStream = FileInputStream(tempFile)

val targetFile = File(downloadsFolder, "targetFileName.pdf")
val isTargetFileCreated = targetFile.createNewFile()
if (!isTargetFileCreated) {
    // handle error: unable to create file
    return
}

FileOutputStream(targetFile).use { outputStream -> 
    tempInputStream.copyTo(outputStream)
}

确保从后台线程或 IO 协程调用它。

我已经解决了这个问题。我一直以为我的模拟器已经安装了 PDF reader(因为其他模拟器也有),但事实并非如此。 activity 无法打开,因为没有 PDF reader。

修复:安装 PDF Reader。