Как сохранить файлы с помощью File API в папку, выбранную пользователем в Android 11?

#android #save #file-permissions #storage-access-framework #android-11

#Android #Сохранить #файл-права доступа #хранилище-доступ-фреймворк #android-11

Вопрос:

Я очень смущен Scoped Storage и Storage Access Framework (SAF) и всеми ограничениями.. Мне нужно использовать File API , а не Uri , так что:
Android API level <= 29 (Android 10) сохранить в /storage/emulated/0 works (with requestLegacyExternalStorage ).
Android API level = 30 (Android 11) сохранить в /storage/emulated/0 does not work ( IOException: Operation not permitted ) .

Environment.getExternalStorageDirectory() устарело. Хорошо, итак getExternalFilesDirs() , в Android 11:

 ctx.getExternalFilesDirs(): /storage/emulated/0/Android/data/<package name>/files //External storage in internal memory
ctx.getExternalFilesDirs(): /storage/16F4-3A1C/Android/data/<package name>/files //SDcard
 

работает, потому что это хранилище приложения. Но пользователи хотят иметь папку приложения в корневом каталоге внешнего хранилища /storage/emulated/0/MySpecificFolder или SD /storage/16F4-3A1C/MySpecificFolder -карты. Я работаю с File API тем, что должно снова работать (в отличие от Android10).

Как я могу выполнить запись в каталог конкретного пользователя, например, в /storage/emulated/0/MySpecificFolder ?

Я пытался использовать:

 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, PICK_FOLDER);
 

который открывает файловый менеджер. Пользователь создает новый каталог (поскольку root не может его использовать): /storage/emulated/0/MySpecificFolder . Далее я пытаюсь создать новый файл с помощью:

 File nomedia = new File("/storage/emulated/0/MySpecificFolder", ".nomedia");
if (!nomedia.exists()) {
    nomedia.createNewFile();
}
 

но это не работает IOException: Operation not permitted . Вероятно, существует проблема с разрешением на запись.

Эта строка работает:

 DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");
 

который работает с. Uri Почему это невозможно использовать File API ? Когда я вызываю createFile() which uses Uri , это работает, но когда я вызываю createNewFile() which uses File API , это не работает. Таким образом, пользователь может выбрать собственный каталог, но только при работе с приложением Uri ?

Как получить path (для последующего использования File API ) не только из SAF Uri .

 // Get Uri from Storage Access Framework.
Uri treeUri = data.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
Log.i(TAG, "Tree uri: " treeUri.getPath());  //returns /tree/primary:My
Log.i(TAG, "Picked dir: " pickedDir.getUri().getPath()); //returns /tree/primary:My/document/primary:My
 

Мне нужно использовать File API , потому что app. создает файлы видео фото данные, которые должны быть вместе.

Вопрос: Возможно ли, чтобы пользователь сам выбирал путь создавал папку (возможно, через SAF) и возвращал File (дескриптор файла) новой созданной папки пользователем в приложение?

Комментарии:

1. «Мне нужно использовать File API, потому что app. создает файлы видео фото данные, которые должны быть вместе» — создайте эти файлы getFilesDir() , затем скопируйте их в выбранное пользователем дерево документов. Или выберите SDK, которые позволяют вам работать с потоками, а не с файлами. «Возможно ли, чтобы пользователь сам выбирал путь создавал папку (вероятно, через SAF) и возвращал файл (дескриптор файла) новой созданной папки пользователем в приложение?» — не a File . Вы можете получить дескрипторы файлов для Uri via ContentResolver .

2. Может быть, это то, что вам нужно: github.com/anggrayudi/SimpleStorage

Ответ №1:

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

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

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