使用系统对话框打开任何文件类型进行查看

Open any file type using the system dialog for viewing

在我的应用程序中,我希望用户能够 select 他们想要的任何文件(.mp4、.pdf 等),在应用程序中显示文件名和扩展名,最后允许他们使用系统对话框打开引用的文件。我已经成功打开文件选择器对话框,获取 selected 文件的路径和信息,但我无法理解如何使用该文件的路径来触发 OS 对话框将处理文件打开过程。我已经阅读了一些关于 SAF 和 ACTION_OPEN_DOCUMENT 行动的内容,但我似乎无法理解这是否有必要或什至如何去做。

这是我的文件检索过程:

private fun openFilePicker() { 
   val intent = Intent(Intent.ACTION_GET_CONTENT)
   intent.type = "*/*"
   startActivityForResult(intent, PICKFILE_RESULT_CODE)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            PICKFILE_RESULT_CODE -> if (resultCode == RESULT_OK) {
                val filePath: String? = data?.data?.path
                if (filePath != null) attachmentsAdapter.addFilePath(filePath) else Toast.makeText(
                    requireContext(),
                    "Something went wrong, please try again!",
                    Toast.LENGTH_SHORT
                ).show()
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }

我知道引入 SAF 是为了改善用户的隐私,并且应用程序最初只能访问自己的目录(我认为还有一些 public 目录),但我真的需要做一些事情,比如创建我自己的目录,将引用的文件复制到那里,然后做任何我需要做的事情来打开它们?

根据 CommonsWare 的回答更新:

如 CommonsWare 所述,诀窍是简单地避免使用返回的 URI 的路径,而是使用 URI 本身。详情请参阅他们的回答。

此外,由于我只使用文件的 URI,因此获取文件名和扩展名的方式有点不同。以下是如何使用 Cursor 完成此操作:

private fun getFileNameWithExtensionFromUri(currentFileUri: String): String? {
    val returnCursor: Cursor? = context.contentResolver.query(Uri.parse(currentFileUri), null, null, null, null)
    /*
     * Get the column indexes of the data in the Cursor,
     * move to the first row in the Cursor, get the data,
     * and display it.
     */
    val nameIndex = returnCursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
    returnCursor?.moveToFirst()
    val fileName = returnCursor?.getString(nameIndex!!)
    returnCursor?.close()
    return fileName
}

Here's my file retrieval process

data?.data?.path 通常不会 return 文件系统路径。

I'm having trouble understanding how to go about using that file's path to trigger the OS dialog that will handle the file opening process

Android 没有“OS 处理文件打开过程的对话框”,至少我会使用这些术语。

如果您想尝试打开一些可以查看内容的应用程序,请创建一个 ACTION_VIEW Intent:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            PICKFILE_RESULT_CODE -> if (resultCode == RESULT_OK) {
                data?.data?.let { uri ->
                  try {
                    startActivity(Intent(Intent.ACTION_VIEW, uri)).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                  } catch (e: Exception) {
                    Toast.makeText(
                      requireContext(),
                      "Something went wrong, please try again!",
                      Toast.LENGTH_SHORT
                    ).show()
                  }
                }
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }

try/catch 很重要,因为您允许用户 select 任何类型的内容,并且可能没有安装支持查看的应用程序该特定类型的内容。

您至少需要设置文件路径和正确的 mime 类型。

val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf")
intent.setDataAndType(Uri.parse("file://$filePath"), mime)