Возникает ошибка «Ошибка открытия: EFAULT (Неверный адрес)», когда okhttp пытается отправить выбранное изображение из PhotoPicker.
Эта ошибка возникает ТОЛЬКО в том случае, если изображение было выбрано из Photo Picker на Android 13 (в версиях без Photo Picker все работает!).
Что означает код:
Пользователь выбирает изображение из Photo Picker.
Получите uri изображения и сохраните файл в теле, там тоже все работает:
File imgFile = FilesHelper.INSTANCE.getFileFromUri(this, imgUri);
postBody.setPhoto(imgFile);
@Throws(Exception::class)
fun getFileFromUri(context: Context, uri: Uri): File? {
var path: String? = null
if ("content".equals(uri.scheme, ignoreCase = true)) {
path = getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
path = uri.path
}
return if (!path.isNullOrEmpty()) File(path) else null
}
private fun getDataColumn(context: Context, uri: Uri,
selection: String?, selectionArgs: Array<String?>?): String? {
var cursor: Cursor? = null
val column = MediaStore.Images.Media.DATA
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val column_index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
cursor?.close()
}
return null
}
Но когда тело отправляется как составное,
final Map<String, RequestBody> multipart = new HashMap<>(2);
multipart.put("product",
RequestBody.create(MediaType.parse("application/json"),
BaseApplication.getGson().toJson(postBody)));
multipart.put("image\"; filename=\"%1.jpg\"",
RequestBody.create(MediaType.parse("image/jpeg"),
postBody.getPhoto())); // type File
....
serverApi.sendBody(multipart);
....
в logCat было показано предупреждение:
*
/sdcard/.transforms/synthetic/picker/0/com.android.providers.media.photopicker/media/1000000019.jpg: open failed: EFAULT (Bad address)*
а затем Retrofit/okhttp выдает исключение.
Дооснащенная версия "com.squareup.retrofit2:retrofit:2.9.0"
Разрешения в AndroidManifest, которые предоставляются перед выбором изображения:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--Android 13 permissions-->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
И android:requestLegacyExternalStorage="true"
в <приложении> тоже.
Запрашиваем разрешения:
if (VERSION.SDK_INT >= 33) arrayOf(Manifest.permission.READ_MEDIA_IMAGES) else arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
Могу ли я получить и отправить это изображение без использования разрешения MANAGE_EXTERNAL_STORAGE? Потому что приложение распространяется через Google Play и не является файловым менеджером или чем-то в этом роде. Может быть, мне следует скопировать файл во внутреннюю папку приложения или что?
1 ответ
Что ж, найдено решение: предоставить разрешение на чтение URI.
private void onImagePicked(Uri imgUri){
if(imgUri!=null) {
try {
grantUriPermission(getPackageName(),imgUri,Intent.FLAG_GRANT_READ_URI_PERMISSION);
File imgFile = FilesHelper.INSTANCE.getFileFromUri(this, imgUri);
postBody.setPhoto(imgFile);
} catch (Exception e) {
...
}
}
}