Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Requesting Android Permissions at Run Time

Published? true
FormatLanguage: WikiFormat

Problem:

In Android 6 and later, you must check permissions at runtime in addition to specifying them in the manifest.

Solution:

To access resources protected by "dangerous" permissions you must: 1) Check if the user has already granted permission before accessing a resource 2) Explicitly request permissions if they are not granted 3) Have an alternate course of action so the application does not crash if the permission is not granted

Discussion:

1) Check if the user has already granted permission before accessing a resource

Before accessing any protected resource, call checkSelfPermission( permission) on Activity. It will return either PERMISSION_GRANTED or PERMISSION_DENIED.

Example: if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

  // If you get here then you have the permission and can do some work.

}

2) Explicitly request permissions if they are not granted

If the permission was not granted then call requestPermissions on Activity

void requestPermissions (String[] permissions,

               int requestCode)

You have to provide a callback for the response

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);

Example:

// Constant for the call back private static int REQUEST_EXTERNAL_STORAGE = 1; ... // Request the permission from the user ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE },

                   REQUEST_EXTERNAL_STORAGE);

// Callback handler for the eventual response:

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions,

int[] grantResults) {
  boolean granted = true;
  if (requestCode == REQUEST_EXTERNAL_STORAGE) {
           // Received permission result for external storage permission.
            Log.i(TAG, "Received response for external storage permission request.");
               // Check if the permissions have been granted
               if (grantResults.length > 0 ) {
                   for (int result : grantResults) {
                       if (result != PackageManager.PERMISSION_GRANTED) {
                           granted = false;
                       }
                   }
               } else {
                   granted = false;
               }

... // If granted is true: carry on and perform the action // Calling checkSelfPermission() will now return PackageManager.PERMISSION_GRANTED

You can provide more information to the user about why the permissions are required.

Call boolean shouldShowRequestPermissionRationale (String permission) on Activity.

If the user has previously refused to grant permissions then this method will return true giving you the opportunity to display extra information as to why they should grant the permission.

       if (ActivityCompat.shouldShowRequestPermissionRationale(this,
               Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
           // Provide an additional explanation to the user if the permission was not granted
           // and the user would benefit from additional context for the use of the permission.
           Log.i(TAG,
                   "Displaying WRITE_EXTERNAL_STORAGE permission rationale to provide additional context.");
           Snackbar.make(mLayout, R.string.external_storage_rationale,
                   Snackbar.LENGTH_INDEFINITE)
                   .setAction(R.string.ok, new View.OnClickListener() {
                       @Override
                       public void onClick(View view) {
                           ActivityCompat.requestPermissions(MainActivity.this,
                                   new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},
                                   REQUEST_EXTERNAL_STORAGE);
                       }
                   }).show();