Если вы являетесь Android-разработчиком, то, возможно, знаете о недавнем изменении политики Google Play в отношении разрешения READ_MEDIA_IMAGES. К сожалению, мы не знали. В этом посте поделимся опытом того, как добавление этого разрешения в манифест заблокировало нам возможность выпустить приложение в альфа-канал, и почему вы должны быть осторожны, прежде чем добавлять это разрешение в свой проект.
Пример использования
Что мы хотели создать: кнопку открытия галереи с предварительным просмотром, которая отображает превью последнего изображения из потока камеры.
Чтобы реализовать нечто подобное, приложение может запросить доступ ко всем изображениям, а затем запросить последнее из них с помощью MediaStore API:
private fun getLatestImageUri(): Uri? { val projection = arrayOf( MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, MediaStore.Images.ImageColumns.DATE_TAKEN, MediaStore.Images.ImageColumns.MIME_TYPE ) val sortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC" return context?.contentResolver?.query( // uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI, // projection = projection, // selection = null, // selectionArgs = null, // sortOrder = sortOrder )?.use { cursor -> if (cursor.moveToFirst()) { // Read the first row only val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) val id = cursor.getLong(idColumn) return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) } null } }
Поскольку этот запрос сможет получать результаты из внешних источников (обратите внимание, мы используем EXTERNAL_CONTENT_URI
), только если приложение имеет к ним доступ, мы должны запросить разрешение на доступ к изображениям в рантайме.
Согласно документации, READ_EXTERNAL_STORAGE
не имеет эффекта, начиная с API уровня 33. Если ваше приложение получает доступ к медиафайлам других приложений, нам нужно запросить одно или несколько из этих разрешений: READ_MEDIA_IMAGES
, READ_MEDIA_VIDEO
, READ_MEDIA_AUDIO
. Именно так мы и поступили.
Поскольку наше приложение поддерживает минимальную версию SDK 29, нам нужно было запросить два разных разрешения:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
READ_EXTERNAL_STORAGE
был необходим для устройств под управлением Android 10-12 (API 29-32)READ_MEDIA_IMAGES
требовалось для устройств под управлением Android 13+ (API 33 и выше)
В процессе разработки все шло хорошо, но когда мы попытались выложить обновление на наш альфа-канал в Play Store, мы столкнулись с серьезной проблемой.
Отказ Play Store
22 января 2025 года Google ввел новую политику, требующую от разработчиков предоставления декларации, обосновывающей использование READ_MEDIA_IMAGES
. Если эта форма не была отправлена (или не была одобрена), обновления приложения блокировались.
Вот точное сообщение об ошибке, которое мы получили:
22 января 2025 года: Разработчики должны представить декларацию. Обратите внимание на следующее:
Разработчики, не предоставившие заполненную форму декларации к этой дате, будут заблокированы в обновлении своего приложения.
Присмотревшись повнимательнее, мы поняли, что критерии одобрения очень строгие. Именно поэтому Google предупредил разработчиков за 2 года, чтобы они успели соответствовать требованиям. Следующие сценарии использования точно будут затронуты:
- Приложения галереи (приложения, предназначенные для управления пользовательскими медиафайлами)
- Приложения для редактирования фотографий
- Приложения для социальных сетей с функциями обмена изображениями.
Такие приложения, как Instagram*, используют это разрешение, потому что их основные сценарии использования соответствуют поддерживаемым:
Однако наш вариант использования — отображение предварительного просмотра последнего изображения из галереи — может относиться как к «широкому доступу», так и к «редкому использованию», в зависимости от того, как вы это видите.
Если Play считает наш случай использования единичным, нам предлагается не использовать это разрешение. Если бы мы захотели обосновать использование «широким доступом», нам пришлось бы подавать декларацию и ждать, пока они одобрят или отклонят ее, а это лотерея.
Основываясь на предыдущем опыте блокировки приложения из-за использования опасных разрешений (еще один случай отказа был связан с READ_CALL_LOG
, который мы решили только удалением этого разрешения), мы решили, что выиграть эту битву будет непросто, и решили, что пока лучше воздержаться от этого разрешения.
Решение
Мы изменили функцию, чтобы избежать ненужных задержек и разблокировать релиз. На данный момент самое простое решение следующее:
В дальнейшем нам придется либо планировать выпуск этой фичи должным образом, либо представить ее в качестве «широкого доступа» и надеяться на лучшее, либо вложить больше средств в поиск альтернативного подхода, не требующего дополнительных разрешений, для получения доступа к последнему изображению из потока камеры.
Подумайте дважды, прежде чем использовать READ_MEDIA_IMAGES
Если вы решили добавить READ_MEDIA_IMAGES
в свое приложение, мы настоятельно рекомендуем:
- Прочитать официальную политику Google
- Оценить свой сценарий использования — спланировать релиз. Если ваше приложение не является галерейным, фото- или медиа-приложением, ожидайте некоторой вероятности отказа и имейте План B.
- Заранее протестировать свое приложение — если вы не уверены, что ваш вариант использования будет одобрен, быстро протестируйте обновление с разрешением. Так как у нас быстрая обратная связь, между разработкой и релизом прошло совсем немного времени, и мы смогли обнаружить эту проблему.
- Рассмотреть альтернативные решения — поговорите с вашими дизайнерами. На данный момент мы используем жестко прописанное изображение для кнопки. Вы также можете использовать Media Store API без запроса полного доступа к изображениям, то есть у вас будет доступ только к изображениям, полученным вашим приложением (используйте
INTERNAL_CONTENT_URI
), и, возможно, этого будет достаточно для вашего случая использования.
Мы надеемся, что этот пост поможет другим разработчикам избежать ненужных разочарований. Если вы сталкивались с подобными проблемами или нашли обходные пути, не стесняйтесь поделиться своим опытом.
Счастливого Андроида!