Bagaimana cara menyimpan file dengan File API ke lokasi yang dipilih pengguna di Android 11?

Saya sangat bingung dengan Scoped Storage dan Storage Access Framework (SAF) dan semua batasan.. Saya perlu menggunakan File API, bukan Uri, jadi:
Android API level ‹= 29 (Android 10) simpan ke /storage/emulated/0 berfungsi (dengan requestLegacyExternalStorage).
Android API level = 30 (Android 11) simpan ke /storage/emulated/0 tidak berfungsi (IOException: Operation not permitted).

Environment.getExternalStorageDirectory() tidak digunakan lagi. Oke, jadi getExternalFilesDirs() Di 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

berfungsi, karena ini adalah penyimpanan aplikasi. Namun pengguna ingin memiliki folder aplikasi di root penyimpanan eksternal /storage/emulated/0/MySpecificFolder atau kartu sd /storage/16F4-3A1C/MySpecificFolder. Saya bekerja dengan File API yang seharusnya berfungsi kembali (tidak seperti Android10).

Bagaimana saya bisa menulis ke direktori khusus pengguna, misalnya ke /storage/emulated/0/MySpecificFolder?

Saya mencoba menggunakan:

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

yang membuka Manajer file. Pengguna membuat direktori baru (karena root tidak dapat menggunakan): /storage/emulated/0/MySpecificFolder. Selanjutnya saya mencoba membuat file baru melalui:

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

tapi tidak berhasil IOException: Operation not permitted. Mungkin ada masalah dengan izin menulis.

Baris ini berfungsi:

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

yang bekerja dengan Uri. Mengapa tidak bisa menggunakan File API? Saat saya menelepon createFile() yang menggunakan Uri, itu berfungsi, tetapi ketika saya menelepon createNewFile() yang menggunakan File API, itu tidak berfungsi. Jadi pengguna dapat memilih direktori sendiri, tetapi hanya ketika aplikasi bekerja dengan Uri?

Cara mendapatkan path (untuk digunakan nanti dengan File API) dari SAF, tidak hanya 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

Saya perlu menggunakan File API, karena app. membuat file video+foto+data yang perlu disatukan.

Pertanyaan: Apakah mungkin bagi pengguna untuk memilih jalurnya sendiri + membuat folder (mungkin melalui SAF) dan mengembalikan File (deskriptor file) dari folder yang baru dibuat oleh pengguna ke aplikasi?


person t0m    schedule 16.12.2020    source sumber
comment
Saya perlu menggunakan File API, karena app. membuat file video+foto+data yang harus digabungkan -- buat file tersebut di getFilesDir(), lalu salin ke pohon dokumen pilihan pengguna. Atau, pilih SDK yang memungkinkan Anda bekerja dengan aliran, bukan file. Apakah mungkin bagi pengguna untuk memilih jalurnya sendiri + membuat folder (mungkin melalui SAF) dan mengembalikan File (deskriptor file) dari folder yang baru dibuat oleh pengguna ke aplikasi? -- bukan File. Anda bisa mendapatkan deskriptor file untuk Uri melalui ContentResolver.   -  person CommonsWare    schedule 16.12.2020
comment
Mungkin ini yang Anda perlukan: github.com/anggrayudi/SimpleStorage   -  person Anggrayudi H    schedule 18.12.2020


Jawaban (1)


Di Android 11, setiap aplikasi cukup menulis ke direktori publik di penyimpanan eksternal menggunakan kelas File lama.

Jangan biarkan pengguna memilih lokasi karena untuk tindakan lebih lanjut Anda perlu menggunakan SAF.

Jika Anda ingin membiarkan pengguna memilih antara Dokumen, Unduhan, Alarm, DCIM, Gambar, dan sebagainya, gunakan daftar kecil dengan Pembuat Peringatan.

person blackapps    schedule 16.12.2020