Izin Runtime dan Layanan Google Play

Mulai 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 perlu memastikan bahwa aplikasi berperilaku seperti yang diharapkan saat pengguna mengaktifkan atau menonaktifkan izin tertentu.

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

Sebaiknya kelola ekspektasi pengguna dalam menetapkan 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 mendeklarasikan API yang ingin Anda gunakan dalam file AndroidManifest.xml, pastikan 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), ini berarti 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:

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 diperlukan aplikasi Anda belum diberikan oleh pengguna, metode requestPermissions harus dipanggil untuk meminta pengguna memberikannya. Respons dari pengguna dicatat dalam callback onRequestPermissionsResult. Aplikasi Anda harus menerapkannya 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.

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 aplikasi dan pengguna sebelumnya telah menolak permintaan izin, aplikasi Anda harus menampilkan penjelasan tambahan sebelum meminta izin lagi. Pengguna kemungkinan besar memberikan izin jika mereka memahami alasan perlunya izin tersebut dan manfaat langsungnya bagi mereka.

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

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 akan memvalidasi bahwa aplikasi tersebut memiliki semua izin yang diperlukan. connect() gagal saat grup izin yang diperlukan oleh layanan Google Play tidak ada.

Jika panggilan ke connect() gagal, pastikan aplikasi Anda menangani kegagalan koneksi dengan benar. Jika layanan Google Play tidak memiliki izin, Anda dapat memanggil startResolutionForResult() untuk memulai alur pengguna guna 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 klien dibuat instance-nya dengan Activity) atau notifikasi baki sistem (jika klien dibuat instance-nya dengan Context) yang dapat diketuk oleh pengguna untuk memulai intent resolusi izin. Panggilan akan diantrekan dan dicoba lagi setelah izin diberikan.