#android #xamarin
#Android #xamarin
Вопрос:
Я пытался получить реальный путь из средства выбора намерений в Xamarin Android, и он отлично работает во всех версиях Android, кроме Android 10. В Android 10 uri содержимого выглядит следующим образом
содержимое://com.android.providers.downloads.documents/document/msf:180
Комментарии:
1. Если у вас есть какие-либо вопросы, не стесняйтесь задавать.
2. @Nouf попробуйте эту библиотеку PICkit
Ответ №1:
после получения URI файла изображения, конечно, нам нужно отредактировать этот файл, сжав его, после чего получить реальный путь к файлу. если вы ориентируетесь на SDK 30, это моя реализация с использованием хранилища с ограниченной областью действия 😉 не забудьте проголосовать за мой ответ.
import android.content.ContentValues
import android.content.Context
import android.content.res.AssetFileDescriptor
import android.&raphics.Bitmap
import android.&raphics.BitmapFactory
import android.&raphics.Ima&eDecoder
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 fra&ment,
* ima&eSelectedUri: uri that return from any pick picture library it usually return inside on activity response method
* appFolderName: name of folder that will &enerate to save compressin& ima&es ;)
* createdIma&eCompressedName : random name of new compressed ima&e
*/
fun compressGetIma&eFilePath(
mContext: Context,
ima&eSelectedUri: Uri,
appFolderName: Strin&,
createdIma&eCompressedName: Strin& = System.currentTimeMillis().toStrin&()
): Strin& {
//re&ion Gettin& the photo to process it
val bitmap = if (Build.VERSION.SDK_INT &&t;= Build.VERSION_CODES.P) {
Ima&eDecoder.decodeBitmap(Ima&eDecoder.createSource(mContext.contentResolver, ima&eSelectedUri))
} else {
mContext.contentResolver.openInputStream(ima&eSelectedUri)?.use { inputStream -&&t;
BitmapFactory.decodeStream(inputStream)
}
}
// endre&ion
//re&ion save photo to &allery usin& Scoped stora&e
val values = ContentValues().apply {
put(MediaStore.Ima&es.Media.DISPLAY_NAME, createdIma&eCompressedName)
put(MediaStore.Ima&es.Media.MIME_TYPE, "ima&e/jpe&")
put(MediaStore.Ima&es.Media.RELATIVE_PATH, "Pictures/$appFolderName/")
put(MediaStore.Ima&es.Media.IS_PENDING, 1)
}
val collection = MediaStore.Ima&es.Media.&etContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val ima&eUri = mContext.contentResolver.insert(collection, values)
//endre&ion
//re&ion save ima&e
mContext.contentResolver.openOutputStream(ima&eUri!!).use { out -&&t;
bitmap!!.compress(Bitmap.CompressFormat.PNG, 100, out)
}
values.clear()
values.put(MediaStore.Ima&es.Media.IS_PENDING, 0)
mContext.contentResolver.update(ima&eUri, values, null, null)
//endre&ion
//re&ion &et file path of content uri
val file = File(mContext.cacheDir, "$createdIma&eCompressedName.pn&")
try {
val assetFileDescriptor: AssetFileDescriptor = mContext.contentResolver.openAssetFileDescriptor(ima&eUri, "r")!!
val inputStream = FileInputStream(assetFileDescriptor.fileDescriptor)
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
inputStream.close()
outputStream.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
//endre&ion
return file.path
}
}
так просто, если вы хотите настроить таргетинг на старые и новые устройства, просто выполните оператор if, чтобы проверить версию Android, если она больше или равна android Q, используйте мой метод, иначе используйте свой старый метод.
Ответ №2:
В Android 10 по умолчанию включено хранилище с ограниченным доступом. Это означает, что вы не можете напрямую получить доступ к пути внешнего хранилища — посмотрите здесь.
Вы можете сделать то, что предлагается, установив значение requestLe&acyExternalStora&e в вашем приложении. true
AndroidManifest.xml , но имейте в виду, что это будет работать только для tar&etSdk 29, а не для 30 .
Если вы пытаетесь получить доступ к мультимедиа, это следует сделать через MediaStore. В противном случае взгляните на документы с областью хранения.
Комментарии:
1. Интересно, какое отношение все это имеет к опубликованной проблеме.
2. @blackapps Поскольку идентификатор документа в uri содержимого имеет вид msf: 89, следовательно, я не могу получить реальный путь к файлу. Как только я получу реальный путь, я должен отправить его в стороннее облако чатов, чтобы они получили файл и сохранили его в своем облаке.
3. Извините, но мой комментарий здесь был, конечно, не для вас. Но для вас есть один в другом месте. Пожалуйста, отреагируйте на это, отредактировав свой пост.
4. @blackapps Как я объяснял в самом первом абзаце, вы не можете получить доступ к пути внешнего хранилища начиная с Android 10. Я также предоставил временное обходное решение (флаг манифеста), а также правильный способ реализации доступа к мультимедиа через MediaStore и ссылку на соответствующие документы. Я не понимаю, что вы нашли неясным или неактуальным.
5. Вопрос о том, как получить доступ к внешнему хранилищу, не был вопросом оригинального плаката. OP хотел получить путь только для uri. Пожалуйста, перечитайте.
Ответ №3:
Вы можете запросить имя файла, а затем построить путь.
-
Запрашивает имя файла:
public static strin& &etFileName(Context context, Android.Net.Uri uri) { ICursor cursor = null; strin&[] projection = { MediaStore.MediaColumns.DisplayName }; try { cursor = context.ContentResolver.Query(uri, projection, null, null, null); if (cursor != null amp;amp; cursor.MoveToFirst()) { int index = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.DisplayName); return cursor.GetStrin&(index); } } finally { if (cursor != null) if (cursor != null) { cursor.Close(); } } return null; }
Создайте путь:
strin& fileName = &etFileName(context, uri);
strin& filePath = Android.OS.Environment.ExternalStora&eDirectory "/Download/" fileName;