Request App Permissions

Every Android app runs in a limited-access sandbox. If an app needs to use resources or information outside of its own sandbox, the app has to request the appropriate permission. You declare that your app needs a permission by listing the permission in the app manifest and then requesting that the user approve each permission at runtime (on Android 6.0 and higher).

The basic principles are as follows:

  • Ask for permissions in context, when the user starts to interact with the feature that requires it.
  • Don't block the user. Always provide the option to cancel an educational UI flow related to permissions.
  • If the user denies or revokes a permission that a feature needs, gracefully degrade your app so that the user can continue using your app, possibly by disabling the feature that requires the permission.
  • Don't assume any system behavior.

This page walks through the step-by-step process of adding permissions to your app and requesting these permissions at runtime as needed.

Add permissions to the manifest

On all versions of Android, to declare that your app needs a permission, put a <uses-permission> element in your app manifest, as a child of the top-level <manifest> element.

For example, an app that needs to access the internet would have this line in the manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- other permissions go here -->

    <application ...>
        ...
    </application>
</manifest>

The system's behavior after you declare a permission depends on how sensitive the permission is. Some permissions are considered "normal" so the system immediately grants them upon installation. Other permissions are considered "dangerous" so the user must explicitly grant your app access. For more information about the different kinds of permissions, see Protection levels.

Check for permissions

If your app needs a dangerous permission, you must check whether you have that permission every time you perform an operation that requires that permission. On Android 6.0 (API level 23) and higher, users can revoke dangerous permissions from any app at any time.

Determine whether your app was already granted the permission

To check if the user has already granted your app a particular permission, pass that permission into the ContextCompat.checkSelfPermission() method. This method returns either PERMISSION_GRANTED or PERMISSION_DENIED, depending on whether your app has the permission.

Explain why your app needs the permission

If the ContextCompat.checkSelfPermission() method returns PERMISSION_DENIED, call shouldShowRequestPermissionRationale() to check whether your app should show an educational UI to the user. In this UI, describe why the feature, which the user wants to enable, needs a particular permission.

Request the permission

After the user views an educational UI and gains insight into why your app needs a particular permission, or after shouldShowRequestPermissionRationale() returns false, starting with AndroidX Activity 1.2.0-alpha02 you can show the permission system dialog by using the ActivityResult APIs with the RequestMultiplePermissions contract. Your app registers an ActivityResultCallback on instantiation and receives an ActivityResultLauncher When it is time to request permissions, it passes the permissions it wants into the launch() call. This method functions asynchronously and provides the user with a prompt. After the user responds to the prompt, the given ActivityResultCallback is executed.

Note: Your app cannot customize the dialog that appears when you call launch(). To provide more information or context to the user, change your app's UI so that it's easier for users to understand why a feature in your app needs a particular permission. For example, you might change the text in the button that enables the feature.

Also, the text in the system permission dialog references the permission group associated with the permission that you requested. This permission grouping is designed for system ease-of-use, and your app shouldn't rely on permissions being within or outside of a specific permission group.

The following code snippet demonstrates the recommended process of checking for a permission, and requesting a permission from the user when necessary:

Kotlin

// register the permissions callback. This can be done as a class val, or a
// lateinit var in onAttach() or onCreate()
val requestPermissions = registerForActivityResult(RequestMultiplePermissions()
    ) { result ->
        // the result from RequestMultiplePermissions is a map linking each
        // request permission to a boolean of whether it is GRANTED

        // check if the permission is granted
        if (result[Manifest.permission.REQUESTED_PERMISSION]) {
            // it was granted
        } else {
            // it was not granted
        }
    }
when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
        performAction(...)
    }
    shouldShowRequestPermissionRationale(...) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected. In this UI,
        // include a "cancel" or "no thanks" button that allows the user to
        // continue using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // We can request the permission by launching the ActivityResultLauncher
        requestPermissions.launch(...)
        // The registered ActivityResultCallback gets the result of the request.
    }
}

Java

// register the permissions callback. This can be done as a class val, or a
// lateinit var in onAttach() or onCreate()
ActivityResultLauncher<String[]> mRequestPermissions =
    registerForActivityResult(new RequestMultiplePermissions(),
        new ActivityResultCallback<Map<String, Boolean>>() {
            @Override
            public void onActivityResult(Map<String, Boolean> result) {
                // the result from RequestMultiplePermissions is a map linking
                // each request permission to a boolean of whether it is GRANTED

                // check if the permission is granted
                if (result.get(Manifest.permission.REQUESTED_PERMISSION)) {
                    // it was granted
                } else {
                    // it was not granted
                }
            }
        });
if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected. In this UI,
    // include a "cancel" or "no thanks" button that allows the user to
    // continue using your app without granting the permission.
    showInContextUI(...);
} else {
    // We can request the permission by launching the ActivityResultLauncher
    mRequestPermissions.launch(...);
    // The registered ActivityResultCallback gets the result of the request.
}

Handle the permissions request response

When the user responds to your app's permission request, the system invokes your registered ActivityResultCallback's onActivityResult() method, passing it the user response to the permission dialog as shown in the following code snippet:

Kotlin

ActivityResultLauncher<String[]> requestPermissions =
    registerForActivityResult(RequestMultiplePermissions()) {
        for(String permission: map) {
            when (permission) {
                    Manifest.permission.REQUESTED_PERMISSION -> {
                        // If request is cancelled, the result map is empty.
                        if (map.isNotEmpty() && map[permission]) {
                            // Permission is granted. Continue the action or workflow
                            // in your app.
                        } else {
                            // Explain to the user that the feature is unavailable because
                            // the features requires a permission that the user has denied.
                            // At the same time, respect the user's decision. Don't link to
                            // system settings in an effort to convince the user to change
                            // their decision.
                        }
                        return
                    }

                // Add other 'when' lines to check for other
                // permissions this app might request.
                else -> {
                    // Ignore all other requests.
                }
            }
        }
    }

Java

ActivityResultLauncher<String[]> mRequestPermissions = 
    registerForActivityResult(new RequestMultiplePermissions(),
    new ActivityResultCallback<Map<String, Boolean>>() {
        @Override
        public void onActivityResult(Map map) {
            for(String permission: map) {
                switch (permission) {
                    case Manifest.permission.REQUESTED_PERMISSION: {
                        // If request is cancelled, the result map is empty.
                        if (!map.isEmpty() && map.get(permission)) {
                            // Permission is granted. Continue the action or workflow
                            // in your app.
                        } else {
                            // Explain to the user that the feature is unavailable because
                            // the features requires a permission that the user has denied.
                            // At the same time, respect the user's decision. Don't link to
                            // system settings in an effort to convince the user to change
                            // their decision.
                        }
                        return;
                    }

                    // Other 'case' lines to check for other
                    // permissions this app might request.
                }
            }
        }
    });

Handle permission denial

If the user denies a permission request, your app should help users understand the implications of denying the permission. In particular, your app should make users aware of the features that don't work because of the missing permission. When you do so, keep the following best practices in mind:

  • Guide the user's attention. Highlight a specific part of your app's UI where there's limited functionality because your app doesn't have the necessary permission. Several examples of what you could do include the following:

    • Show a message where the feature's results or data would have appeared.
    • Display a different button that contains an error icon and color.
  • Be specific. Don't display a generic message; instead, mention which features are unavailable because your app doesn't have the necessary permission.

  • Don't block the user interface. In other words, don't display a full-screen warning message that prevents users from continuing to use your app at all.

In certain situations, the permission might be denied automatically, without the user taking any action. (Similarly, a permission might be granted automatically as well.) It's important to not assume anything about automatic behavior. Each time your app needs to access functionality that requires a permission, you should check that your app is still granted that permission.

For more information about the ActivityResult APIs, see Getting a result from an activity.

To provide the best user experience when asking for app permissions, also see App Permissions Best Practices.

Request to become the default handler if necessary

Some apps depend on access to sensitive user information related to call logs and SMS messages. If you want to request the permissions specific to call logs and SMS messages and publish your app to the Play Store, you must prompt the user to set your app as the default handler for a core system function before requesting these runtime permissions.

For more information on default handlers, including guidance on showing a default handler prompt to users, see the guide on permissions used only in default handlers.

Declare permissions by API level

To declare a permission only on devices that support runtime permissions—that is, devices running Android 6.0 (API level 23) or higher—include the uses-permission-sdk-23 tag instead of the uses-permission tag.

When using either of these tags, you can set the maxSdkVersion attribute to specify that, on devices running a higher version, a particular permission isn't needed.

Additional resources

For additional information about permissions, read these articles:

To learn more about requesting permissions, download the following sample apps:

  • Android RuntimePermissionsBasic Sample Java | Kotlin