Layanan Google Play dan izin runtime

Sejak Android 6.0 Marshmallow, Android menggunakan model izin yang menyederhanakan proses penginstalan dan update otomatis aplikasi. Izin diminta saat runtime, bukan sebelum penginstalan aplikasi. Selain itu, pengguna dapat memilih untuk menolak izin tertentu. Untuk memberikan fleksibilitas ini kepada pengguna, Anda harus memastikan bahwa aplikasi Anda berperilaku seperti yang diharapkan saat pengguna mengaktifkan atau menonaktifkan izin tertentu.

Layanan Google Play sendiri memiliki izin runtime yang dapat ditolak pengguna secara terpisah dari izin yang secara khusus diminta oleh aplikasi Anda. Layanan Google Play secara otomatis mendapatkan semua izin yang diperlukan untuk mendukung API-nya. Namun, aplikasi Anda tetap harus memeriksa dan meminta izin runtime sebagaimana diperlukan dan menangani error dengan tepat jika pengguna telah menolak izin layanan Google Play yang diperlukan untuk API yang digunakan aplikasi Anda.

Sebaiknya kelola ekspektasi pengguna dalam menyetel izin yang mungkin diperlukan oleh runtime. Praktik terbaik berikut akan membantu Anda menghindari potensi masalah.

Prasyarat

Anda harus mendeklarasikan izin dalam file AndroidManifest.xml. Contoh:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Panduan

Memverifikasi izin sebelum memanggil API

Setelah Anda mendeklarasikan API yang ingin digunakan dalam file AndroidManifest.xml, verifikasi bahwa Anda memiliki izin yang diperlukan sebelum memanggil API. Hal ini dapat dilakukan menggunakan metode checkSelfPermission dari ActivityCompat atau ContextCompat.

Jika panggilan menampilkan nilai salah (false), artinya izin tidak diberikan dan Anda harus menggunakan requestPermissions untuk memintanya. Respons terhadap hal ini ditampilkan dalam callback yang akan Anda lihat di langkah berikutnya.

Contoh:

Kotlin

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
            // Request Permissions Now
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
    } else {
        // permission has been granted, continue as usual
        val locationResult = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

Java

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Request Permissions Now
        ActivityCompat.requestPermissions(
            this,
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
            REQUEST_LOCATION_PERMISSION_CODE);
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

Menerapkan callback izin permintaan

Jika izin yang diperlukan aplikasi Anda belum diberikan oleh pengguna, metode requestPermissions harus dipanggil untuk meminta pengguna memberikan izin tersebut. Respons dari pengguna diambil di callback onRequestPermissionsResult. Aplikasi Anda harus menerapkan hal ini dan selalu memeriksa nilai yang ditampilkan karena permintaan dapat ditolak atau dibatalkan. Anda juga dapat meminta dan memeriksa beberapa izin sekaligus. Contoh berikut hanya memeriksa satu izin.

Kotlin

    fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) {
               // We can now safely use the API we requested access to
               val locationResult: Task = LocationServices
                    .getFusedLocationProviderClient(this /* Context */)
                    .lastLocation // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

Java

    public void onRequestPermissionsResult(int requestCode,
                                            String[] permissions,
                                            int[] grantResults) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if(grantResults.length == 1
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // We can now safely use the API we requested access to
                Task locationResult = LocationServices
                    .getFusedLocationProviderClient(this /** Context */)
                    .getLastLocation(); // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

Menampilkan alasan izin

Jika izin yang diminta aplikasi Anda diperlukan untuk fitur inti aplikasi dan pengguna telah menolak permintaan izin sebelumnya, aplikasi Anda harus menampilkan penjelasan tambahan sebelum meminta izin lagi. Pengguna cenderung memberikan izin jika mereka memahami alasan izin tersebut diperlukan dan manfaat langsungnya bagi mereka.

Dalam hal ini, sebelum memanggil requestPermissions, Anda harus memanggil shouldShowRequestPermissionRationale. Jika menampilkan nilai benar (true), Anda harus membuat beberapa UI untuk menampilkan konteks tambahan izin.

Misalnya, kode Anda mungkin terlihat seperti ini:

Kotlin

    private const val REQUEST_LOCATION_PERMISSION_CODE = 2
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        if ActivityCompat.shouldShowRequestPermissionRationale(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
        }
    } else {
        // Permission has already been granted, continue as usual
        val locationResult: Task = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

Java

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        private static final int REQUEST_LOCATION_PERMISSION_CODE = 2;
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this, new String[]{Manifest.permission.LOCATION_FINE},
                REQUEST_LOCATION_PERMISSION_CODE);
        }
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

Panggilan API layanan Google Play akan otomatis menampilkan dialog (jika klien di-instance dengan Activity) atau notifikasi area notifikasi sistem (jika klien di-instance dengan Context) yang dapat diketuk pengguna untuk memulai intent penyelesaian izin. Panggilan akan dimasukkan dalam antrean dan dicoba lagi setelah izin diberikan.