Skip to content Skip to sidebar Skip to footer

How Request Permissions With Jetpack Compose?

How should be implemented requesting permission from Jetpack Compose View? I'm trying implement application accessing Camera with Jetpack Compose. I tried example from How to get C

Solution 1:

as compose_version = '1.0.0-beta04' and

implementation 'androidx.activity:activity-compose:1.3.0-alpha06'

you can do request permission as simple as this:

@Composable
fun ExampleScreen() {
    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission Accepted: Do something
            Log.d("ExampleScreen","PERMISSION GRANTED")

        } else {
            // Permission Denied: Do something
            Log.d("ExampleScreen","PERMISSION DENIED")
        }
    }
    val context = LocalContext.current

    Button(
        onClick = {
            // Check permission
            when (PackageManager.PERMISSION_GRANTED) {
                ContextCompat.checkSelfPermission(
                    context,
                    Manifest.permission.READ_EXTERNAL_STORAGE
                ) -> {
                    // Some works that require permission
                    Log.d("ExampleScreen","Code requires permission")
                }
                else -> {
                    // Asking for permission
                    launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
                }
            }
        }
    ) {
        Text(text = "Check and Request Permission")
    }
}


Solution 2:

Check out Google Accompanist's Jetpack Compose Permissions.

Bear in mind that, at the time of writing, the API is still considered experimental and will require the @ExperimentalPermissionsApi annotation when used.


Solution 3:

Google has a library called "Accompanist". It has many help libraries and one of them is the Permission Library.

Check: Library: https://github.com/google/accompanist/

Documentation: https://google.github.io/accompanist/permissions/

Example:

Setup in build.gradle file:

repositories {
    mavenCentral()
}

dependencies {

implementation "com.google.accompanist:accompanist-permissions:<latest_version>"

}

Implementation in Code

 @Composable

 private fun RequiresCameraPermission(navigateToSettingsScreen: () -> Unit){

// Track if the user doesn't want to see the rationale any more.
var doNotShowRationale by rememberSaveable { mutableStateOf(false) }

val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA)
PermissionRequired(
    permissionState = cameraPermissionState,
    permissionNotGrantedContent = {
        if (doNotShowRationale) {
            Text("Feature not available")
        } else {
            Column {
                Text("The camera is important for this app. Please grant the permission.")
                Spacer(modifier = Modifier.height(8.dp))
                Row {
                    Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
                        Text("Ok!")
                    }
                    Spacer(Modifier.width(8.dp))
                    Button(onClick = { doNotShowRationale = true }) {
                        Text("Nope")
                    }
                }
            }
        }
    },
    permissionNotAvailableContent = {
        Column {
            Text(
                "Camera permission denied. See this FAQ with information about why we " +
                        "need this permission. Please, grant us access on the Settings screen."
            )
            Spacer(modifier = Modifier.height(8.dp))
            Button(onClick = navigateToSettingsScreen) {
                Text("Open Settings")
            }
        }
    }
) {
    Text("Camera permission Granted")
}

}


Solution 4:

A little late but this might help as I had the problem today:

With ContextAmbient.current it is not guaranteed that you have an activity or fragment thus I created my own ambient for handling permissions.

val AmbientPermissionHandler: ProvidableAmbient<PermissionHandler> =
    ambientOf { throw IllegalStateException("permission handler is not initialized") }

// Activity:
private val permissionHandler = PermissionHandler(this)
// onCreate:
setContent {
    Providers(
        AmbientPermissionHandler provides permissionHandler
    ) {/* Composable Contnent */}

Usage:

@Composable
fun PermissionHandler(
    permissions: Array<out String>,
    requestCode: Int,
    granted: @Composable() () -> Unit,
    denied: @Composable() () -> Unit,
    deniedPermanently: (@Composable() () -> Unit)? = null,
    rational: (@Composable() () -> Unit)? = null,
    awaitResult: (@Composable() () -> Unit)? = null,
) {
    val permissionHandler = AmbientPermissionHandler.current
    val (permissionResult, setPermissionResult) = remember(permissions) { mutableStateOf<PermissionResult?>(null) }
    LaunchedEffect(Unit) {
        setPermissionResult(permissionHandler.requestPermissionsSuspend(requestCode, permissions))
    }
    when (permissionResult) {
        is PermissionResult.PermissionGranted -> granted()
        is PermissionResult.PermissionDenied -> denied()
        is PermissionResult.PermissionDeniedPermanently -> deniedPermanently?.invoke()
        is PermissionResult.ShowRational -> rational?.invoke()
        null -> awaitResult?.invoke()
    }
}

Implementation of PermissionHandler with dependency https://github.com/sagar-viradiya/eazypermissions

class PermissionHandler(
    private val actualHandler: AppCompatActivity,
) {
    suspend fun requestPermissionsSuspend(requestCode: Int, permissions: Array<out String>): PermissionResult {
        return PermissionManager.requestPermissions(actualHandler, requestCode, *permissions)
    }

    fun requestPermissionsWithCallback(requestCode: Int, permissions: Array<out String>, onResult: (PermissionResult) -> Unit) {
        actualHandler.lifecycleScope.launch {
            onResult.invoke(PermissionManager.requestPermissions(actualHandler, requestCode, *permissions))
        }
    }
}

If you prefer a callback the second function works also.


Solution 5:

/**
 * Composable helper for permission checking
 *
 * onDenied contains lambda for request permission
 *
 * @param permission permission for request
 * @param onGranted composable for [PackageManager.PERMISSION_GRANTED]
 * @param onDenied composable for [PackageManager.PERMISSION_DENIED]
 */
@Composable
fun ComposablePermission(
    permission: String,
    onDenied: @Composable (requester: () -> Unit) -> Unit,
    onGranted: @Composable () -> Unit
) {
    val ctx = LocalContext.current

    // check initial state of permission, it may be already granted
    var grantState by remember {
        mutableStateOf(
            ContextCompat.checkSelfPermission(
                ctx,
                permission
            ) == PackageManager.PERMISSION_GRANTED
        )
    }
    if (grantState) {
        onGranted()
    } else {
        val launcher: ManagedActivityResultLauncher<String, Boolean> =
            rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()) {
                grantState = it
            }
        onDenied { launcher.launch(permission) }
    }
}

Post a Comment for "How Request Permissions With Jetpack Compose?"