Register now for Android Dev Summit 2019!

Gunakan Scoped Directory Access

Beberapa aplikasi, seperti aplikasi foto, biasanya hanya memerlukan akses ke direktori tertentu dalam penyimpanan eksternal, misalnya direktori Pictures. Pendekatan yang ada untuk mengakses penyimpanan eksternal tidak didesain untuk dengan mudah memberikan akses direktori yang ditargetkan untuk jenis aplikasi ini. Contoh:

  • Meminta READ_EXTERNAL_STORAGE atau WRITE_EXTERNAL_STORAGE dalam manifes Anda akan memberikan akses ke semua direktori publik di penyimpanan eksternal, yang mungkin lebih banyak daripada yang dibutuhkan aplikasi.
  • Menggunakan Storage Access Framework biasanya meminta pengguna untuk memilih direktori melalui UI sistem, yang tidak diperlukan jika aplikasi selalu mengakses direktori eksternal yang sama.

Android 7.0 menyediakan API yang disederhanakan untuk mengakses direktori penyimpanan eksternal umum.

Mengakses direktori penyimpanan eksternal

Gunakan kelas StorageManager untuk mendapatkan instance StorageVolume yang sesuai. Kemudian, buat intent dengan memanggil metode StorageVolume.createAccessIntent() dari instance tersebut. Gunakan intent ini untuk mengakses direktori penyimpanan eksternal. Untuk mendapatkan daftar semua volume yang tersedia, termasuk volume media lepas-pasang, gunakan StorageManager.getStorageVolumes().

Jika Anda memiliki informasi tentang file spesifik, gunakan StorageManager.getStorageVolume(File) untuk mendapatkan StorageVolume yang berisi file tersebut. Panggil createAccessIntent() pada StorageVolume guna mengakses direktori penyimpanan eksternal untuk file tersebut.

Di volume kedua, seperti kartu SD eksternal, teruskan null saat memanggil createAccessIntent() untuk meminta akses ke seluruh volume, sebagai ganti direktori spesifik. createAccessIntent() akan mengembalikan null jika Anda meneruskan null ke volume utama atau meneruskan nama direktori yang tidak valid.

Cuplikan kode berikut adalah contoh cara membuka direktori Pictures dalam penyimpanan bersama utama:

Kotlin

    val sm = getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val volume: StorageVolume = sm.primaryStorageVolume
    volume.createAccessIntent(Environment.DIRECTORY_PICTURES).also { intent ->
        startActivityForResult(intent, request_code)
    }
    

Java

    StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
    StorageVolume volume = sm.getPrimaryStorageVolume();
    Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
    startActivityForResult(intent, request_code);
    

Sistem ini mencoba untuk memberikan akses ke direktori eksternal, dan jika diperlukan akan mengonfirmasi akses dengan pengguna yang menggunakan UI yang disederhanakan:

Gambar 1. Sebuah aplikasi yang meminta akses ke direktori Pictures.

Jika pengguna memberi akses, sistem akan memanggil penggantian onActivityResult() Anda dengan kode hasil RESULT_OK, dan data intent yang berisi URI. Gunakan URI yang diberikan untuk mengakses informasi direktori, serupa dengan menggunakan URI yang dikembalikan oleh Storage Access Framework.

Jika pengguna tidak memberi akses, sistem akan memanggil penggantian onActivityResult() Anda dengan kode hasil RESULT_CANCELED, dan data intent null.

Mendapatkan akses ke direktori eksternal tertentu juga akan memperoleh akses ke subdirektori dalam direktori tersebut.

Mengakses direktori pada media lepas-pasang

Untuk menggunakan Scoped Directory Access guna mengakses direktori pada media lepas-pasang, tambahkan BroadcastReceiver yang akan mendengarkan notifikasi MEDIA_MOUNTED terlebih dahulu, misalnya:

    <receiver
        android:name=".MediaMountedReceiver"
        android:enabled="true"
        android:exported="true" >
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_MOUNTED" />
            <data android:scheme="file" />
        </intent-filter>
    </receiver>
    

Saat pengguna memasang media lepas-pasang, seperti kartu SD, sistem akan mengirimkan notifikasi MEDIA_MOUNTED. Notifikasi ini memberikan objek StorageVolume dalam data intent yang dapat digunakan untuk mengakses direktori pada media lepas-pasang. Contoh berikut mengakses direktori Pictures pada media lepas-pasang.

Kotlin

    // BroadcastReceiver has already cached the MEDIA_MOUNTED
    // notification Intent in mediaMountedIntent
    val volume =
        mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME) as StorageVolume
    volume.createAccessIntent(Environment.DIRECTORY_PICTURES).also { intent ->
        startActivityForResult(intent, request_code)
    }
    

Java

    // BroadcastReceiver has already cached the MEDIA_MOUNTED
    // notification Intent in mediaMountedIntent
    StorageVolume volume = (StorageVolume)
        mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
    Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
    startActivityForResult(intent, request_code);
    

Praktik terbaik

Jika memungkinkan, pertahankan URI akses direktori eksternal agar Anda tidak perlu berulang kali meminta akses kepada pengguna. Setelah pengguna memberikan akses, panggil getContentResolver() dan dengan panggilan ContentResolver yang dikembalikan takePersistableUriPermission() beserta URI akses direktori. Sistem akan tetap menggunakan URI, serta permintaan akses berikutnya akan menunjukkan RESULT_OK dan tidak akan menampilkan UI konfirmasi kepada pengguna.

Jika pengguna menolak akses ke direktori eksternal, jangan segera meminta akses lagi. Berulang kali meminta akses akan menghasilkan pengalaman pengguna yang buruk. Jika permintaan ditolak oleh pengguna dan aplikasi meminta akses lagi, UI akan menampilkan kotak centang Jangan tanya lagi.

Gambar 1. Sebuah aplikasi membuat permintaan kedua untuk mengakses media lepas-pasang.

Jika pengguna memilih Jangan tanya lagi dan menolak permintaan, semua permintaan berikutnya untuk direktori yang diberikan dari aplikasi Anda akan ditolak secara otomatis, serta UI permintaan tidak akan ditampilkan ke pengguna.