Android 在安卓10上从URI获取真实文件路径,在安卓10中内容URI的后缀为msf:documentid
我试图从Xamarin Android中的intent chooser获得真正的路径,它在除Android 10之外的所有Android版本中都能正常工作。在安卓10中,内容uri类似于Android 在安卓10上从URI获取真实文件路径,在安卓10中内容URI的后缀为msf:documentid,android,xamarin,Android,Xamarin,我试图从Xamarin Android中的intent chooser获得真正的路径,它在除Android 10之外的所有Android版本中都能正常工作。在安卓10中,内容uri类似于 content://com.android.providers.downloads.documents/document/msf%3A180Android 10默认启用了作用域存储。这意味着您无法直接访问外部存储路径-请看一看 您可以通过在应用程序的AndroidManifest.xml中将设置为true来执行
content://com.android.providers.downloads.documents/document/msf%3A180Android 10默认启用了作用域存储。这意味着您无法直接访问外部存储路径-请看一看 您可以通过在应用程序的AndroidManifest.xml中将设置为
true
来执行建议的操作,但请记住,这只适用于targetSdk 29,不适用于30+
如果您试图访问媒体,则应通过。
否则,请查看。在获取图像文件的URI之后,当然我们需要通过压缩来编辑此文件,在获得真实的文件路径之后。如果您以SDK 30为目标,这是我使用作用域存储的实现;) 别忘了给我的答案投票
import android.content.ContentValues
import android.content.Context
import android.content.res.AssetFileDescriptor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
/**
* Created by Mostafa Anter on 11/5/20.
*/
object PhotoHelper{
@RequiresApi(Build.VERSION_CODES.Q)
/**
* mContext: context from activity or fragment,
* imageSelectedUri: uri that return from any pick picture library it usually return inside on activity response method
* appFolderName: name of folder that will generate to save compressing images ;)
* createdImageCompressedName : random name of new compressed image
*/
fun compressGetImageFilePath(
mContext: Context,
imageSelectedUri: Uri,
appFolderName: String,
createdImageCompressedName: String = System.currentTimeMillis().toString()
): String {
//region Getting the photo to process it
val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(mContext.contentResolver, imageSelectedUri))
} else {
mContext.contentResolver.openInputStream(imageSelectedUri)?.use { inputStream ->
BitmapFactory.decodeStream(inputStream)
}
}
// endregion
//region save photo to gallery using Scoped storage
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, createdImageCompressedName)
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/$appFolderName/")
put(MediaStore.Images.Media.IS_PENDING, 1)
}
val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val imageUri = mContext.contentResolver.insert(collection, values)
//endregion
//region save image
mContext.contentResolver.openOutputStream(imageUri!!).use { out ->
bitmap!!.compress(Bitmap.CompressFormat.PNG, 100, out)
}
values.clear()
values.put(MediaStore.Images.Media.IS_PENDING, 0)
mContext.contentResolver.update(imageUri, values, null, null)
//endregion
//region get file path of content uri
val file = File(mContext.cacheDir, "$createdImageCompressedName.png")
try {
val assetFileDescriptor: AssetFileDescriptor = mContext.contentResolver.openAssetFileDescriptor(imageUri, "r")!!
val inputStream = FileInputStream(assetFileDescriptor.fileDescriptor)
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
inputStream.close()
outputStream.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
//endregion
return file.path
}
}
如果你想针对新旧设备,只需做if语句检查android版本,如果android Q更大或相等,请使用我的方法,否则请使用你的旧方法。你可以查询文件名,然后构建路径
- 查询文件名:
public static string getFileName(Context context, Android.Net.Uri uri) { ICursor cursor = null; string[] projection = { MediaStore.MediaColumns.DisplayName }; try { cursor = context.ContentResolver.Query(uri, projection, null, null, null); if (cursor != null && cursor.MoveToFirst()) { int index = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.DisplayName); return cursor.GetString(index); } } finally { if (cursor != null) if (cursor != null) { cursor.Close(); } } return null; }
string fileName = getFileName(context, uri);
string filePath = Android.OS.Environment.ExternalStorageDirectory + "/Download/" + fileName;
如果您有任何问题,请随时提问。@Nou如果尝试此库,我想知道这一切与发布的问题有什么关系。@blackapps,因为内容uri中的文档id为msf:89,因此我无法获取文件的真实路径。一旦我得到了真正的路径,我必须发送到第三方聊天云,这样他们将获得文件并将其存储在他们的云中。对不起,我在这里的评论当然不是为你。但是在别的地方有一个是给你的。请通过编辑您的帖子作出反应。@blackapps正如我在第一段中解释的,自Android 10以来,您无法访问外部存储路径。我还提供了一个临时解决方案(manifest标志),以及通过MediaStore和相关文档链接实现访问媒体的正确方法。我不明白你发现什么不清楚或不相关。如何访问外部存储不是原始海报的问题。OP只想获取uri的路径。请重读。