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。
我知道有很多类似的主题,但它们要么已经过时,要么不适用于 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。