Как работать с Uri, Intent и доступом к файлам в Android (Java)
Коротко: используйте Uri с ContentResolver для чтения/записи и FileProvider для безопасной передачи файлов через Intent — добавляйте флаги доступа (FLAG_GRANT_READ_URI_PERMISSION) и при необходимости takePersistableUriPermission() для долгосрочного доступа.
Основы Uri в Android
Uri — это абстрактный идентификатор ресурса: content://, file://, http:// и т. д. Для создания используйте:
Uri u1 = Uri.parse("content://com.example/app/files/1");
Uri u2 = Uri.fromFile(new File("/path/to/file.jpg")); // избегайте на Android 7+
Полезные методы: getScheme(), getLastPathSegment(), getPath() (не всегда надежен для content://). Всегда проверяйте схему: если content, читайте через ContentResolver, а не напрямую с файловой системы.
Если getScheme() возвращает content, используйте getContentResolver().openInputStream(uri) для чтения.
Использование Intent с Uri: выбор и передача файлов
Типичные Intent'ы:
ACTION_GET_CONTENT/ACTION_OPEN_DOCUMENT— выбрать файл (получаете Uri вonActivityResult/ Activity Result API).ACTION_VIEW— открыть ресурс у внешнего приложения.ACTION_SEND— поделиться файлом.
Пример выбора изображения:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_PICK);
В onActivityResult:
Uri uri = data.getData(); // используйте ContentResolver для чтения
При отправке Uri другому приложению:
- Генерируйте
content://черезFileProvider. - Добавьте
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)(и WRITE при необходимости). - Укажите тип MIME с
setDataAndType()илиsetType().
Доступ к файлам и FileProvider (надежный способ)
Начиная с Android 7, file:// Uri могут привести к FileUriExposedException. Решение — FileProvider.
- Манифест:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.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>
<files-path name="my_files" path="."/>
</paths>
- Генерация Uri:
File f = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "photo.jpg");
Uri photoUri = FileProvider.getUriForFile(context, "com.example.myapp.fileprovider", f);
intent.putExtra(Intent.EXTRA_STREAM, photoUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Если не включить grantUriPermissions="true" или не добавить флаг разрешения в Intent, получатель не сможет открыть Uri — будет Permission Denial.
Чтение и запись через ContentResolver
Чтение:
try (InputStream in = getContentResolver().openInputStream(uri)) {
byte[] bytes = in.readAllBytes();
}
Запись (если провайдер позволяет):
try (OutputStream out = getContentResolver().openOutputStream(uri)) {
out.write(data);
}
Для долгосрочного доступа к документам используйте takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) после получения Uri от ACTION_OPEN_DOCUMENT.
Частые ошибки
- FileUriExposedException — используйте
FileProvider. - Permission Denial — забыли
FLAG_GRANT_READ_URI_PERMISSION. - Ожидание реального файлового пути из
content://— многие провайдеры не возвращают путь; не пытайтесь использоватьnew File(uri.getPath()). - Неправильные
file_paths.xml— указывайте корректные корневые каталоги (external-files-path,files-pathи т.д.).
FAQ
- Как получить реальный путь файла из
content://? Часто невозможно или ненужно. Работа ведётся черезContentResolver(InputStream). Извлечение реального пути ненадёжно и зависит от провайдера. - Нужен ли
MANAGE_EXTERNAL_STORAGE? Обычно нет. Предпочитайте Scoped Storage иACTION_OPEN_DOCUMENT.MANAGE_EXTERNAL_STORAGEподходит лишь для специальных случаев и жестко проверяется в Google Play. - Как дать постоянный доступ к документу?
Используйте
ACTION_OPEN_DOCUMENT, затемgetContentResolver().takePersistableUriPermission().
Эти практики покроют большинство сценариев работы с Uri в Android на Java: чтение/запись, выбор файлов, безопасная передача через Intent и обход распространённых ошибок.