Введение
С Android 10+ Google ввёл Scoped Storage — новую модель хранения, которая ограничивает прямое приложение-специфическое взаимодействие с файлами во внешней памяти. Это повышение приватности иногда приводит к «исчезновению» данных, если приложение не обновлено для работы с новой моделью. В этом руководстве вы узнаете, как перенести существующие данные в соответствующее пространство хранения, сохранив доступность и целостность файлов.
Требования
- Устройство под управлением Android 10 (API 29) или выше (рекомендуется Android 12+ для стабильной работы File Provider).
- Разработанный Android-код приложения (Android Studio проект), в котором нужно выполнить миграцию.
- Доступ к компьютеру с
adb(Android Debug Bridge) для массовых операций. - Базовое понимание Kotlin/Java и XML-разметки AndroidManifest.
- Резервная копия важных файлов на случай непредвиденных ситуаций.
Пошаговая инструкция
Шаг 1: Проверьте текущую структуру хранения
Откройте Настройки → Хранилище → Internal storage и найдите директорию вашего приложения (обычно /storage/emulated/0/app_name/). Запишите относительный путь, поскольку он понадобится для перемещения данных.
Шаг 2: Создайте app-specific директорию с использованием File Provider
Добавьте в AndroidManifest.xml объявление провайдера:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Создайте ресурс res/xml/file_paths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_files" path="."/>
<images-path name="my_images" path="pictures/"/>
<documents-path name="my_docs" path="Documents/"/>
</paths>
Теперь приложение может безопасно выдавать content:// URI для файлов, находящихся в этих директориях.
Шаг 3: Переместите существующие файлы в новую директорию
Для массового перемещения через ADB выполните:
adb shell "mv /storage/emulated/0/app_name/old_dir/* /storage/emulated/0/app_name/files/"
Для автоматизированного перемещения в коде Kotlin:
val src = File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "old")
val dst = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
src.listFiles()?.forEach { file ->
val target = File(dst, file.name)
file.copyTo(target, overwrite = true)
}
Шаг 4: Обновите URI для существующих файлов
Если приложение ранее использовало прямые file:// URI, замените их на URI, полученные через File Provider:
val uri = FileProvider.getUriForFile(this, "com.example.fileprovider", imageFile)
Теперь вы можете безопасно передавать uri в Intent или ContentResolver.
Шаг 5: Проверьте доступность через MediaStore (для медиафайлов)
Для изображений и видео добавьте записи в MediaStore:
val imageUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "new_image.jpg")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.DATA, imagePath)
}
contentResolver.insert(imageUri, values)
Данные становятся доступны через системные приложения (Галерея, Фотографии) без дополнительных прав.
Шаг 6: Запустите приложение и проверьте работу
Запустите приложение, откройте раздел «Мои файлы» или «Галерея». Убедитесь, что все ранее существовавшие файлы доступны по тем же именам. Если что-то пропало, найдите их в DCIM, Pictures или Documents — именно туда их поместил File Provider.
Проверка результата
- Все файлы отображаются в приложении.
- Системные инструменты (например, файловый менеджер) также видят новые директории (
/storage/emulated/0/app_name/files/). - URI, выданные через File Provider, открываются корректно в других приложениях.
- Нет предупреждений о доступе к файлам в панели «Приложения → Разрешения».
Возможные проблемы
- Потеря доступа к файлам после перезагрузки – убедитесь, что вы добавили
<provider>сandroid:exported="false"и правильно настроилиauthorities. - Неправильные пути в MediaStore – укажите правильный
MIME_TYPEиDATA; проверьте, что путь существует в файловой системе. - Сбой копирования через ADB – проверьте права:
adb shellдолжен запускаться от пользователя, имеющего доступ к/storage/emulated/0. - Файлы всё ещё недоступны – запустите
ContentResolver.loadThumbnailилиMediaScannerConnectionдля обновления индексации.