3.5 Permissions

The manifest file also controls what permissions your application has requested from the user. Apps must be granted the right to use certain functions of the device, from accessing the camera to accessing the internet. Only once the app has requested access, will the system grant the benign ones, and ask the user to explicitly hand over control of the more dangerous ones. For example, knowing the state of the network will be granted automatically, while knowing device location must go through the user first.

The app must publicize all required permissions in AndroidManifest.xml, where they all sit in <uses-permission> tags in the manifest root as a sibling child to the <application> element. The following line declares that this application will request the geo-location of users.

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

When dealing with code that involves permissions, developers must be able to adequately respond to situations where the user has denied the permission to the application (and not crash because of an exception because the permission wasn’t granted).

How can we request permissions?

Before checking out this section, make sure you first check out this!

Step 1: Declare the permission in the Android Manifest file: In Android, permissions are declared in the AndroidManifest.xml file using the uses-permission tag.

<manifest xlmns:android...>
 ...
 <uses-permission android:name=”android.permission.PERMISSION_NAME”/>
 <application ...
</manifest>

Step 2: Check whether permission is already granted or not. If permission isn’t already granted, request the user for the permission: In order to use any service or feature, the permissions are required. Hence we have to ensure that the permissions are given for that. If not, then the permissions are requested.

This step is compromised of multiple steps.

Step 2.1: Register the permissions callback, which handles the user's response to the system permissions dialog. In this case, we can use the ActivityResultLauncher introduced during the explicit intents section to automatically handle actually requesting the permission to the user and giving us the result:


    private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        requestPermissionLauncher =
            registerForActivityResult(ActivityResultContracts.RequestPermission()
            ) { isGranted: Boolean ->
                if (isGranted) {
                    // 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.
                }
            }
        ...
    }

Step 2.2: Check or request the given permission. This code snippet demonstrates the recommended process of checking for a permission, and requesting a permission from the user when necessary:

How does this work if we want to request multiple permissions at once?

Similarly, multiple permissions can be requested at the same time by passing an array of Permissions instead of single permission as input and we get a MutableMap with permissions as keys and grant result as values in the activityResultCallback.

The request permission launcher changes as so:

Ultimately just tailor the conditions to your needs!

The when else block in step 2.2 is dependent on your needs of your permissions but the structure is relatively the same. If you need multiple permissions at once for some API / UI / functionality, expand the first if case to check to see if all the respective permissions are granted.

If I needed to access both the camera and external storage I could do something like this:

This process can be abstracted away as a function!

When multiple permissions are requested, the permission prompts are shown one after another instead of all at once, so users could deny some but allow others, thus you must check if you shouldShowRequestPermissionRationale for each individual permission!

Lastly:

How do we use the new launcher to request multiple permissions?

Instead of passing a singular permission, we pass in an array of the permissions we want to ask for, here's an example below:

Accompanist - Simplifying Permissions

Requesting permissions can be a complex process, but with the help of libraries like Accompanist, handling permissions becomes much easier and streamlined, especially in Jetpack Compose. Here, we introduce the Accompanist library, which simplifies permission handling in Compose-based applications.

Installation

To get started with Accompanist Permissions, add the following dependency to your build.gradle.kts file:

Setup

Declare any required permissions in the AndroidManifest.xml. We'll be working with the ACCESS_FINE_LOCATION and the READ_CONTACTS permissions which changes our manifest as so:

Checking and Requesting Permissions

Accompanist makes checking and requesting permissions straightforward by using rememberPermissionState. Permissions are managed as states in Compose, allowing UI updates based on permission status.

Here’s an example of how to request permissions for fine location and contacts:

Requesting Permissions Flow

  1. Check Permission State: Use rememberPermissionState to check if a permission is granted or not.

  2. Launch Permission Request: If a permission is not granted, call launchPermissionRequest() to show the system permission dialog.

  3. Handle Rationale: If the user denies the permission, shouldShowRationale can be used to show a rationale message explaining why the app needs the permission.

All done! Way more simple!

Last updated

Was this helpful?