ТестированиеМобильное тестированиеИнженер по мобильному тестированию

После обновления Android приложение перестало читать изображение из общей галереи, хотя файл открывается си...

После обновления Android приложение перестало читать изображение из общей галереи, хотя файл открывается системным просмотрщиком. Как проверить, что причина связана с моделью доступа к общему хранилищу, а не с повреждением файла?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Нужно проверить тот же файл через системный просмотрщик и отдельно зафиксировать, каким способом приложение получает к нему доступ: по файловому пути или через предоставленный системой URI. Если файл исправен, но приложение теряет доступ к общему хранилищу либо использует недопустимый прямой путь, причиной, вероятнее всего, является Scoped Storage, а не повреждение данных.

Исторический контекст

Старые версии Android позволяли приложениям работать с общим хранилищем преимущественно через обычные файловые пути. Такой подход упрощал обмен файлами, но давал приложениям слишком широкий доступ к пользовательским данным.

Начиная с Android 10 появилась модель Scoped Storage, ограничивающая произвольный доступ к общему хранилищу. Для выбора пользовательских файлов предназначен системный механизм Storage Access Framework, а для медиаданных — MediaStore. Степень ограничений зависит от версии Android и целевой версии SDK приложения.

Постановка проблемы

Видимость файла в галерее не означает, что приложение может прочитать его по прежнему пути. Система может разрешать просмотр файла через собственный компонент, но отклонять прямой доступ приложения к этому же объекту.

Неверная диагностика приводит к попытке повторно скачать или восстановить исправный файл. В результате появляются дубликаты, потеря пользовательских данных и ложные дефекты в логике работы с изображениями.

Подробное решение

Сначала нужно проверить файл вне приложения: открыть его системным просмотрщиком и, по возможности, другим приложением. Если другие компоненты читают изображение, а мобильное приложение получает отказ в доступе или ошибку открытия, повреждение файла маловероятно.

Затем следует сравнить два сценария: выбор файла через системный документный интерфейс и открытие файла по заранее сохранённому пути. При системном выборе приложение получает URI, разрешённый пользователем и системой. Попытка преобразовать этот URI в обычный путь и открыть его напрямую может быть некорректной: URI не обязан соответствовать доступному файловому пути.

Нужно также проверить версию Android, целевую версию приложения, наличие требуемого разрешения и источник файла. Файл из общей галереи, файл во внутреннем каталоге приложения и файл, переданный другим приложением, подчиняются разным правилам доступа.

Для воспроизводимого теста используют несколько состояний: чистая установка, обновление приложения, выбор нового изображения, повторное открытие ранее выбранного изображения и отзыв разрешения. В логах важно различать отсутствие файла, отказ в доступе, недействительный URI и ошибку декодирования содержимого.

Компромисс состоит в выборе способа хранения. Копирование выбранного файла во внутреннее хранилище повышает надёжность последующего доступа, но расходует место и требует политики очистки. Хранение внешнего URI экономит место, однако доступ может зависеть от выданного разрешения и поведения поставщика документа.

Ситуация из практики

После обновления Android пользователь выбирал фотографию из галереи, но приложение падало при повторном открытии профиля. Проверка показала, что первоначальный выбор проходил успешно, а затем приложение сохраняло только строковое представление пути и пыталось открыть его напрямую.

Рассматривались два варианта. Первый — запросить широкий доступ ко всему хранилищу: это могло быстро устранить симптом, но ухудшало приватность и зависело от версии Android. Второй — сохранять предоставленный URI и читать содержимое через системный механизм; этот вариант лучше соответствовал модели ограниченного доступа, но требовал обработки недействительного или отозванного разрешения.

Выбрали второй вариант, а для часто используемых изображений добавили копирование содержимого во внутреннее хранилище приложения. В тестах отдельно проверили обновление приложения, повторный запуск, отзыв доступа и удаление исходного файла. В результате приложение перестало зависеть от конкретного внешнего пути, а ошибки доступа стали корректно обрабатываться.

Что кандидаты часто упускают

  1. Достаточно ли проверить наличие разрешения на чтение?

Нет. Разрешение само по себе не гарантирует доступ к конкретному объекту. Важно учитывать источник файла, способ его выдачи, версию Android и то, используется ли URI с предоставленными системой правами либо произвольный путь.

Кроме того, пользователь мог выбрать файл через системный интерфейс, но приложение могло не сохранить долгосрочное право доступа или потерять его после восстановления данных. Поэтому тест должен включать повторный запуск и повторное открытие ранее выбранного объекта.

  1. Почему успешное открытие файла в галерее не доказывает, что приложение должно открыть его тем же способом?

Системная галерея может обладать собственными правами или получать временный доступ через системный компонент. Приложение является другим участником модели безопасности и не наследует эти права автоматически.

Следовательно, нужно проверять не только содержимое файла, но и канал передачи доступа: URI, разрешения и способ чтения. Сам факт отображения файла пользователю доказывает его доступность системе, но не произвольному приложению.

  1. Когда разумно копировать файл во внутреннее хранилище приложения?

Копирование оправдано, если приложение должно гарантировать доступ к содержимому независимо от дальнейшей судьбы исходного объекта: например, для аватара, офлайн-документа или вложения черновика. Внутреннее хранилище изолировано от других приложений и обычно не зависит от внешнего URI.

Недостатки — дополнительный расход места, необходимость контролировать дубликаты и удалять ненужные копии. Если файл нужен только для однократной обработки, лучше прочитать его через предоставленный URI без создания постоянной копии.