I wrote utility functions to request/check permissions in Composables (using CompositionLocal).
data class PermissionHandlerValue(
val hasPermission: (String) -> Boolean,
val hasPermissions: (Array<out String>) -> Array<Boolean>,
val requestPermission: (String) -> Unit,
val requestPermissions: (Array<out String>) -> Unit
)
val LocalPermissionHandler = compositionLocalOf<PermissionHandlerValue> { error("No implementation provided!") }
@Composable
fun ProvidePermissionHandler(content: @Composable () -> Unit) {
CompositionLocalProvider(LocalPermissionHandler provides permissionHandlerImpl()) {
content()
}
}
@Composable
fun permissionHandlerImpl(): PermissionHandlerValue {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}
val hasPermission: (String) -> Boolean = { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED }
val hasPermissions: (Array<out String>) -> Array<Boolean> = { it.map { permission -> hasPermission(permission) }.toTypedArray() }
val requestPermission: (String) -> Unit = { launcher.launch(arrayOf(it)) }
val requestPermissions: (Array<out String>) -> Unit = { launcher.launch(it) }
return PermissionHandlerValue(hasPermission, hasPermissions, requestPermission, requestPermissions)
}
@Composable
fun RequirePermission(permission: String, fallback: (@Composable () -> Unit)? = null, content: @Composable () -> Unit) {
val permissionHandler = LocalPermissionHandler.current
if (permissionHandler.hasPermission(permission))
content()
else if (fallback != null)
fallback()
}
It works fine, I can request and check permissions. The problem is that its not reactive, here's an example:
setContent {
ProvidePermissionHandler {
val permissionHandler = LocalPermissionHandler.current
RequirePermission(
permission = Manifest.permission.READ_CONTACTS,
fallback = {
Button(onClick = { permissionHandler.requestPermission(Manifest.permission.READ_CONTACTS)
}) {
Text("Request permission")
}
}
) {
ContactsList()
}
}
}
This composable(RequirePermission
) will only render ContactsList
if the Manifest.permission.READ_CONTACTS
was granted, Otherwise the fallback
component is rendered with a button that when clicked will request the permission.
After permissionHandler.requestPermission()
is called and I grant the permission on the screen the fallback
still shows, instead of the ContactsList
(I have to re-open the app to show it).
Basically the condition in RequirePermission()
is not checked again because there is no recomposition. How can I force RequirePermission()
to recompose?