Izin Runtime dan Layanan Google Play

Sejak Android 6.0 Marshmallow, Android menggunakan model izin yang menyederhanakan penginstalan aplikasi dan proses pembaruan otomatis. Izin diminta pada saat runtime, bukan sebelum penginstalan aplikasi. Selain itu, pengguna dapat memilih untuk menolak izin tertentu. Untuk memberi pengguna fleksibilitas ini, Anda perlu memastikan bahwa aplikasi Anda berperilaku sebagai yang diharapkan ketika pengguna mengaktifkan atau menonaktifkan izin tertentu.

Layanan Google Play sendiri memiliki izin runtime yang dapat dipilih pengguna tolak secara terpisah dari izin akses yang secara khusus diminta oleh aplikasi. Layanan Google Play otomatis mendapatkan semua izin yang diperlukan mendukung API-nya. Namun, aplikasi Anda tetap harus memeriksa dan meminta runtime sesuai kebutuhan dan menangani kesalahan dengan tepat ketika pengguna telah menolak layanan Google Play izin yang diperlukan untuk API yang digunakan aplikasi Anda.

Praktik yang baik adalah untuk mengelola ekspektasi pengguna dalam menetapkan izin yang yang mungkin diperlukan runtime. Praktik terbaik berikut akan membantu Anda menghindari potensi masalah.

Prasyarat

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

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

Panduan

Memverifikasi izin sebelum memanggil API

Setelah Anda mendeklarasikan API yang ingin digunakan di AndroidManifest.xml, pastikan Anda memiliki izin yang diperlukan sebelum memanggil API. Ini dapat dilakukan menggunakan metode checkSelfPermission dari ActivityCompat atau ContextCompat.

Jika panggilan menampilkan nilai false, ini berarti izin tidak diberikan dan Anda harus menggunakan requestPermissions untuk memintanya. Respons untuk pertanyaan ini adalah ditampilkan dalam callback yang akan Anda lihat di langkah berikutnya.

Contoh:

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

Mengimplementasikan callback izin permintaan

Jika izin yang dibutuhkan aplikasi Anda belum diberikan oleh pengguna, Metode requestPermissions harus dipanggil untuk menanyakan pengguna untuk memberinya. Respons dari pengguna dicatat dalam Callback onRequestPermissionsResult. Aplikasi Anda harus terapkan ini dan selalu periksa nilai yang dikembalikan, karena permintaan dapat berupa ditolak atau dibatalkan. Anda juga dapat meminta dan memeriksa beberapa izin di sekali - contoh berikut hanya memeriksa satu izin.

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

Tampilkan alasan izin

Jika izin yang diminta aplikasi Anda diperlukan untuk fitur inti dan pengguna telah menolak permintaan izin sebelumnya, aplikasi Anda harus menampilkan penjelasan tambahan sebelum meminta izin kembali. Pengguna cenderung memberikan izin akses ketika mereka memahami alasan izin dibutuhkan dan segera memanfaatkannya.

Dalam hal ini, sebelum panggilan requestPermissions, Anda harus memanggil shouldShowRequestPermissionRationale. Jika menghasilkan benar, Anda harus membuat beberapa UI untuk menampilkan konteks tambahan izin akses.

Misalnya, kode Anda mungkin terlihat seperti ini:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
    != PackageManager.PERMISSION_GRANTED) {
    // Check Permissions Now
    private static final int REQUEST_LOCATION = 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},
            ACCESS_FINE_LOCATION);
    }
} else {
    // permission has been granted, continue as usual
    Task<Location> locationResult = LocationServices
        .getFusedLocationProviderClient(this /** Context */)
        .getLastLocation();
}

Menangani kegagalan koneksi

Jika aplikasi Anda menggunakan GoogleApiClient yang tidak digunakan lagi, saat Anda memanggil connect(), layanan Google Play memvalidasi bahwa aplikasi tersebut memiliki semua izin yang diperlukan. connect() gagal saat ada grup izin yang dibutuhkan oleh layanan Google Play sendiri akan hilang.

Jika panggilan ke connect() gagal, pastikan aplikasi Anda menangani kegagalan koneksi dengan benar. Jika layanan Google Play sendiri tidak memiliki izin, Anda dapat memanggil startResolutionForResult() untuk memulai alur pengguna untuk memperbaikinya.

Contoh:

@Override
public void onConnectionFailed(ConnectionResult result) {
    if (mResolvingError) {
        // Already attempting to resolve an error.
        return;
    } else if (result.hasResolution()) {
        try {
            mResolvingError = true;
            result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
        } catch (SendIntentException e) {
            // There was an error with the resolution intent. Try again.
            mGoogleApiClient.connect();
        }
    } else {
        // Show dialog using GooglePlayServicesUtil.getErrorDialog()
        showErrorDialog(result.getErrorCode());
        mResolvingError = true;
    }
}

Panggilan API berbasis GoogleApi yang lebih baru akan otomatis menampilkan dialog (jika instance klien dibuat dengan Activity) atau notifikasi baki sistem (jika instance klien akan dibuat dengan Context) yang dapat diketuk oleh pengguna untuk memulai intent resolusi izin. Panggilan akan diantrekan dan dicoba lagi setelah izin akses diberikan.