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

Я очень запутался с Scoped Storage и Storage Access Framework (SAF) и всеми ограничениями.. Мне нужно использовать File API, а не Uri, поэтому:
Уровень Android API ‹= 29 (Android 10) сохранение в /storage/emulated/0 работает (с requestLegacyExternalStorage).
Уровень Android API = 30 (Android 11) сохранение на /storage/emulated/0 не работает (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(), который использует Uri, это работает, но когда я вызываю createNewFile(), который использует 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 (дескриптор файла) новой папки, созданной пользователем, в приложение?


person t0m    schedule 16.12.2020    source источник
comment
Мне нужно использовать File API, потому что app. создает файлы видео+фото+данных, которые должны быть вместе -- создайте эти файлы в getFilesDir(), затем скопируйте их в выбранное пользователем дерево документов. Или выберите SDK, которые позволяют работать с потоками, а не с файлами. Может ли пользователь выбрать собственный путь + создать папку (возможно, через SAF) и вернуть файл (дескриптор файла) новой созданной пользователем папки в приложение? -- не File. Вы можете получить файловые дескрипторы для Uri через ContentResolver.   -  person CommonsWare    schedule 16.12.2020
comment
Возможно, это то, что вам нужно: github.com/anggrayudi/SimpleStorage   -  person Anggrayudi H    schedule 18.12.2020


Ответы (1)


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

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

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

person blackapps    schedule 16.12.2020