Android Version-Specific Permission Handler for Composables in Jetpack Compose

In modern Android development, managing permissions is crucial for ensuring your app functions correctly while respecting user privacy. This guide explores how to handle runtime permissions in Jetpack Compose using the PermissionHandler
composable function.
Understanding the Need for Permissions
Android apps often require access to sensitive data and features, such as location and media. With recent Android updates, managing these permissions has become more nuanced. Here, we present a simple and effective way to request multiple permissions while providing a user-friendly interface.
Implementation of PermissionHandler
Below is thePermissionHandler
function that manages permissions in your Jetpack Compose application. This function checks for necessary permissions based on the Android version and prompts the user to grant them.
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionHandler(
onPermissionsGranted: () -> Unit
) {
val context = LocalContext.current
val activity = context as? Activity
// State to show or hide the dialog
var showDialog by remember { mutableStateOf(false) }
// List of permissions to request based on Android version
val permissions = remember {
mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.CAMERA
).apply {
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> {
// Android 14 (API 34) and above
add(Manifest.permission.READ_MEDIA_IMAGES)
add(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
// Android 13 (API 33)
add(Manifest.permission.READ_MEDIA_IMAGES)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
// Android 10 (API 29)
add(Manifest.permission.ACCESS_MEDIA_LOCATION)
add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> {
// Android 9 (API 28)
add(Manifest.permission.READ_EXTERNAL_STORAGE)
add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
}
}
// State to manage permission requests
val permissionsState = rememberMultiplePermissionsState(permissions)
// Effect to check permission status
LaunchedEffect(permissionsState.allPermissionsGranted) {
if (permissionsState.allPermissionsGranted) {
onPermissionsGranted() // Proceed if permissions are granted
} else {
showDialog = true // Show dialog if permissions are not granted
}
}
// Dialog to request permissions
if (showDialog) {
AlertDialog(
onDismissRequest = { /* Prevent dismissal by tapping outside */ },
title = { Text("Permissions Required") },
text = { Text("This app requires access to your media to function properly. Please grant the requested permissions.") },
confirmButton = {
Button(onClick = {
showDialog = false
permissionsState.launchMultiplePermissionRequest() // Launch permission request
}) {
Text("Grant Permissions")
}
},
dismissButton = {
Button(onClick = {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", context.packageName, null) // Open app settings
}
context.startActivity(intent)
}) {
Text("Open Settings")
}
}
)
}
}
Key Components of the Code
- Permissions Management: The function dynamically creates a list of permissions based on the Android version. This ensures that your app only requests the necessary permissions relevant to the user’s device.
- State Management: The function uses
remember
to create a mutable state variableshowDialog
, controlling the visibility of the permission dialog. - User Interface: An
AlertDialog
is presented to the user, offering them a choice to grant permissions or navigate to the app settings for manual permission management. - Dependencies: Ensure you include the required dependencies in your
build.gradle
file:
dependencies {
implementation "androidx.compose.runtime:runtime:<version>" // Replace <version> with the latest version
implementation "com.google.accompanist:accompanist-permissions:<version>" // Replace <version> with the latest version
}
Conclusion
Handling permissions correctly is crucial for building responsive and user-friendly applications. ThePermissionHandler
function provides a clear, concise way to manage permissions in Jetpack Compose, ensuring that your app adheres to best practices while delivering a seamless user experience. You can significantly simplify permission handling by leveraging the power of Compose and the Accompanist library.