How to ask for user permission with Jetpack Compose

Desilio Neto
3 min readJan 16, 2024

In this tutorial I gonna show you how to ask user permission, if the user denny the permission a dialog will be showed to explain why you app need this permission, if the user denny the permission, it will show the dialog again, if the user denny the permission and check “Don’t ask me again” then it will show a new dialog explain again why the permission is important for the app with an option to go to app settings so the user can change the permission manually. Enough of explanations, let’s code:

Firstly I created an interface to provide the title, description and label of our permission dialog:

interface PermissionDialogTextProvider {
fun getTitle() : String
fun getDescription(isPermanentlyDeclined: Boolean): String
fun getButtonLabel(isPermanentlyDeclined: Boolean): String
}

In this example I’ll be asking for the permission to access the camera, so we need to add this permission to the AndroidManifest.xml

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

Next step I created a class that extends PermissionDialogTextProvider to provide the text we need for the Permission dialog according the permission I asking:

class StoragePermissionDialogTextProvider : PermissionDialogTextProvider {
override fun getTitle(): String = "Permission required"
override fun getDescription(isPermanentlyDeclined: Boolean): String {
return if (isPermanentlyDeclined) {
"It seems you permanently declined the app to access your phone gallery. You can go to the app settings to grant it."
} else {
"This app need to access your camera so it can capture image and videos to use on the app."
}
}
override fun getButtonLabel(isPermanentlyDeclined: Boolean): String {
return if (isPermanentlyDeclined) "Go to settings" else "OK"
}
}

Next I created the Permission Dialog itself, what is basically an dialog with that receives as input the description of the dialog, if the dialog is permanently declined and 3 lambda functions one to dismiss the dialog, other to handle ok or go to app settings button click according if the dialog was permanently declined or not.

@Composable
fun PermissionDialog(
permissionDialogTextProvider: PermissionDialogTextProvider,
isPermanentlyDeclined: Boolean,
onDismiss: () -> Unit,
onOkClick: () -> Unit,
onGoToAppSettingsClick: () -> Unit
) {
Dialog(
onDismissRequest = onDismiss
) {
Surface(shape = RoundedCornerShape(20.dp)) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(16.dp)
) {
Text(
text = permissionDialogTextProvider.getTitle(),
fontWeight = FontWeight.Bold
)

Spacer(modifier = Modifier.height(20.dp))

Text(
text = permissionDialogTextProvider.getDescription(isPermanentlyDeclined)
)

Spacer(modifier = Modifier.height(20.dp))

Button(onClick = {
if (isPermanentlyDeclined) {
onGoToAppSettingsClick()
} else {
onOkClick()
}
}) {
Text(text = permissionDialogTextProvider.getButtonLabel(isPermanentlyDeclined))
}
}
}
}
}

The last part of our puzzle is our main screen that is basically um button to ask the permission, if the permissions has already granted it will show a Toast message otherwise it will show the permission dialog as I explained before:

class MainActivity : ComponentActivity() {

private val permissionRequired = Manifest.permission.CAMERA

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetpackComposePermissionsTheme {
var showPermissionDialog by remember { mutableStateOf(false) }

val storagePermissionResultLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { isGranted ->
if (isGranted) {
Toast
.makeText(this, "Permission granted", Toast.LENGTH_SHORT)
.show()
}
showPermissionDialog = !isGranted
}
)

Scaffold { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,

) {
Button(onClick = {
storagePermissionResultLauncher.launch(permissionRequired)
}) {
Text(text = "Request permission")
}
}
}

if (showPermissionDialog) {
PermissionDialog(StoragePermissionDialogTextProvider(),
isPermanentlyDeclined = !shouldShowRequestPermissionRationale(permissionRequired),
onDismiss = { showPermissionDialog = false },
onOkClick = {
storagePermissionResultLauncher.launch(permissionRequired)
showPermissionDialog = false
},
onGoToAppSettingsClick = {
openAppSettings()
showPermissionDialog = false
}
)
}
}
}
}
private fun openAppSettings() {
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
)
startActivity(intent)
}
}

That’s it this is the code to ask for a single permission, there’s also the option to ask for multiples permissions at the same time but I won’t cover it today because I wanna leave it as simple as possible. The complete code can be found on this repository. If the tutorial was useful for you give me a clap here and also give the project a star on Github. Feel free to answer any question on the comments. Happy coding!

--

--