« Jetpack Compose Runtime Permissions

What is Runtime Permission?

Before Marshmallow (Android 6.0), permissions were handled at install-time and specified in the AndroidManifest.xml within the project. After Marshmallow, permissions must now be requested at runtime before being used. Runtime permissions prevent apps from gaining access to private data without a user’s consent and provide them with additional context and visibility into the types of permissions that applications are either seeking or have been granted.

We will use Google’s accompanist libraries for this

First of all, we need to add some dependency for Runtime Permission:

1dependencies {
2 implementation "com.google.accompanist:accompanist-permissions:0.24.3-alpha"
3}

Now we need to add the permissions in our AndroidManifest.xml file:

1<?xml version="1.0" encoding="utf-8"?>
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.erselankhan.compose">
4
5 <uses-permission android:name="android.permission.CAMERA"/>
6 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
7 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
8
9 <application
10 android:allowBackup="true"
11 android:icon="@mipmap/ic_launcher"
12 android:label="@string/app_name"
13 android:roundIcon="@mipmap/ic_launcher_round"
14 android:supportsRtl="true"
15 android:theme="@style/Theme.Compose">
16 <activity
17 android:name=".MainActivity"
18 android:exported="true"
19 android:label="@string/app_name"
20 android:theme="@style/Theme.Compose">
21 <intent-filter>
22 <action android:name="android.intent.action.MAIN" />
23
24 <category android:name="android.intent.category.LAUNCHER" />
25 </intent-filter>
26 </activity>
27
28 <meta-data
29 android:name="com.google.android.geo.API_KEY"
30 android:value="AIza***************************"/>
31
32 </application>
33
34</manifest>

There are two types of permissions states in Jetpack Compose:

  1. Single Permission State
  2. Multiple Permissions State

Single Permission State:

We will use rememberPermissionState function for a single permission state. This function takes two parameters, the first parameter is for the permission name and the second parameter is for the permission state i.e it is granted or not.

Multiple Permissions State:

We will use rememberMultiplePermissionsState function for multiple permissions state. This function takes two parameters, the first parameter is for the list of permissions names and the second parameter is for the permission states of all the requested permissions.

1val singlePermissionState = rememberPermissionState(
2 Manifest.permission.CAMERA
3) { isGranted ->
4 if (isGranted) {
5 Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
6 } else {
7 Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
8 }
9}
10
11val multiplePermissionsState = rememberMultiplePermissionsState(
12 permissions = listOf(
13 Manifest.permission.WRITE_EXTERNAL_STORAGE,
14 Manifest.permission.READ_EXTERNAL_STORAGE
15 )
16) { permissionStateMap ->
17 if (!permissionStateMap.containsValue(false)) {
18 Toast.makeText(context, "Permissions Granted", Toast.LENGTH_SHORT).show()
19 } else {
20 Toast.makeText(context, "Permissions Denied", Toast.LENGTH_SHORT).show()
21 }
22}

We are just initializing the single and multiple permissions states. We are taking Camera permission by using a single permission state, and taking Read Storage and Write Storage permissions by using multiple permissions states.

Let’s invoke launchPermissionRequest and launchMultiplePermissionRequest functions to take these permissions:

1Column(
2 modifier = Modifier.fillMaxSize(),
3 horizontalAlignment = Alignment.CenterHorizontally,
4 verticalArrangement = Arrangement.Center
5) {
6 Button(onClick = {
7 singlePermissionState.launchPermissionRequest()
8 }) {
9 Text(text = "For Camera Permission")
10 }
11 Button(onClick = {
12 multiplePermissionsState.launchMultiplePermissionRequest()
13 }) {
14 Text(text = "For Storage Permission")
15 }
16}

Here is the full code:

1@OptIn(ExperimentalPermissionsApi::class)
2@Composable
3fun RuntimePermissionScreen(
4
5) {
6
7 val context = LocalContext.current
8 val singlePermissionState = rememberPermissionState(
9 Manifest.permission.CAMERA
10 ) { isGranted ->
11 if (isGranted) {
12 Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
13 } else {
14 Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
15 }
16 }
17
18 val multiplePermissionsState = rememberMultiplePermissionsState(
19 permissions = listOf(
20 Manifest.permission.WRITE_EXTERNAL_STORAGE,
21 Manifest.permission.READ_EXTERNAL_STORAGE
22 )
23 ) { permissionStateMap ->
24 if (!permissionStateMap.containsValue(false)) {
25 Toast.makeText(context, "Permissions Granted", Toast.LENGTH_SHORT).show()
26 } else {
27 Toast.makeText(context, "Permissions Denied", Toast.LENGTH_SHORT).show()
28 }
29 }
30
31 Column(
32 modifier = Modifier.fillMaxSize(),
33 horizontalAlignment = Alignment.CenterHorizontally,
34 verticalArrangement = Arrangement.Center
35 ) {
36 Button(onClick = {
37 singlePermissionState.launchPermissionRequest()
38 }) {
39 Text(text = "For Camera Permission")
40 }
41 Button(onClick = {
42 multiplePermissionsState.launchMultiplePermissionRequest()
43 }) {
44 Text(text = "For Storage Permission")
45 }
46 }
47}

For full working code please visit

https://github.com/anishakd4/JetpackComposeRuntimePermissions