我正在努力寻找这个问题的明确答案。我知道这在某种程度上涉及使用媒体商店,但我不太清楚。
谢谢。
编辑:如果有帮助的话,我目前正在使用 Pixel 2。
如果您的目标是Android 11 API,则无法直接访问文件路径,因为 API 30(Android R) 中有很多限制。随着Android 10(API 29)中引入了作用域存储API ,存储现在分为作用域存储(私有存储)和共享存储(公共存储)。作用域存储是一种您只能访问在作用域存储目录(即 /Android/data/ 或 /Android/media/)中创建的文件的类型。您无法从共享存储(即内部存储/外部 SD 卡存储等)访问文件
共享存储再次进一步分为媒体和下载集合。媒体集合存储图像、音频和视频文件。下载集合将处理非媒体文件。
要了解有关作用域存储和共享存储的更多详细信息,请参阅此链接 - Android 10 和 Android 11 中的作用域存储。
为了获取文档目录路径,我创建了 URI utils 类,它将从 URI 获取文件的路径。
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Log
import android.widget.Toast
import java.io.File
import java.io.FileOutputStream
class UriPathUtils
{
fun getRealPathFromURI(context: Context, uri: Uri): String? {
when {
// DocumentProvider
DocumentsContract.isDocumentUri(context, uri) -> {
when {
// ExternalStorageProvider
isExternalStorageDocument(uri) -> {
//Toast.makeText(context, "From Internal & External Storage dir", Toast.LENGTH_SHORT).show()
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true)) {
if (split.size > 1) {
Environment.getExternalStorageDirectory().toString() + "/" + split[1]
} else {
Environment.getExternalStorageDirectory().toString() + "/"
}
// This is for checking SD Card
} else {
"storage" + "/" + docId.replace(":", "/")
}
}
isDownloadsDocument(uri) -> {
//Toast.makeText(context, "From Downloads dir", Toast.LENGTH_SHORT).show()
val fileName = getFilePath(context, uri)
if (fileName != null) {
return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
}
var id = DocumentsContract.getDocumentId(uri)
if (id.startsWith("raw:")) {
id = id.replaceFirst("raw:".toRegex(), "")
val file = File(id)
if (file.exists()) return id
}
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
return getDataColumn(context, contentUri, null, null)
}
isMediaDocument(uri) -> {
//Toast.makeText(context, "From Documents dir", Toast.LENGTH_SHORT).show()
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
var contentUri: Uri? = null
when (type) {
"image" -> {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
"video" -> {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
"audio" -> {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
else -> {
//non-media files i.e documents and other files
contentUri = MediaStore.Files.getContentUri("external")
val selection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.MediaColumns.RELATIVE_PATH + "=?"
} else "_id=?"
val selectionArgs = arrayOf(Environment.DIRECTORY_DOCUMENTS)
return getMediaDocumentPath(context, contentUri,selection,selectionArgs)
}
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}
isGoogleDriveUri(uri) -> {
Toast.makeText(context, "From Google Drive", Toast.LENGTH_SHORT).show()
return getDriveFilePath(uri, context)
}
/*else -> {
Toast.makeText(context, "Unknown Directory", Toast.LENGTH_SHORT).show()
}*/
}
}
"content".equals(uri.scheme, ignoreCase = true) -> {
//Toast.makeText(context, "From Content Uri", Toast.LENGTH_SHORT).show()
// Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)
}
"file".equals(uri.scheme, ignoreCase = true) -> {
//Toast.makeText(context, "From File Uri", Toast.LENGTH_SHORT).show()
return uri.path
}
}
return null
}
private fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
if (uri == null) return null
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}
private fun getMediaDocumentPath(context: Context, uri: Uri?,selection: String?, selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
if (uri == null) return null
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
//Toast.makeText(context, "From Media Document --- Non Media Path ${cursor.getString(index)} ", Toast.LENGTH_SHORT).show()
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}
private fun getFilePath(context: Context, uri: Uri?): String? {
var cursor: Cursor? = null
val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
try {
if (uri == null) return null
cursor = context.contentResolver.query(uri, projection, null, null,
null)
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
return cursor.getString(index)
}
} finally {
cursor?.close()
}
return null
}
private fun getDriveFilePath(uri: Uri, context: Context): String? {
val returnCursor = context.contentResolver.query(uri, null, null, null, null)
val nameIndex = returnCursor!!.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE)
returnCursor.moveToFirst()
val name = returnCursor.getString(nameIndex)
val size = returnCursor.getLong(sizeIndex).toString()
val file = File(context.cacheDir, name)
try {
val inputStream = context.contentResolver.openInputStream(uri)
val outputStream = FileOutputStream(file)
var read = 0
val maxBufferSize = 1 * 1024 * 1024
val bytesAvailable = inputStream!!.available()
//int bufferSize = 1024;
val bufferSize = Math.min(bytesAvailable, maxBufferSize)
val buffers = ByteArray(bufferSize)
while (inputStream.read(buffers).also { read = it } != -1) {
outputStream.write(buffers, 0, read)
}
Log.e("File Size", "Size " + file.length())
inputStream.close()
outputStream.close()
Log.e("File Path", "Path " + file.path)
Log.e("File Size", "Size " + file.length())
} catch (e: Exception) {
Log.e("Exception", e.message!!)
}
return file.path
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private fun isGoogleDriveUri(uri: Uri): Boolean {
return "com.google.android.apps.docs.storage" == uri.authority || "com.google.android.apps.docs.storage.legacy" == uri.authority
}
}
Run Code Online (Sandbox Code Playgroud)
这个 utils 类将帮助您获取文件路径,只需调用这一行..
contentUri.let { UriPathUtils().getRealPathFromURI(this, it).toString() }
Run Code Online (Sandbox Code Playgroud)
干杯...!
| 归档时间: |
|
| 查看次数: |
7553 次 |
| 最近记录: |