1

I was trying to find out how to request permissions in Jetpack Compose. Found an article in official documentation, but I couldn't figure out how to use it in my case; there's also an answer on Stack Overflow, but I simply couldn't understand it.

I will appreciate if you show some of your examples with explanation, or help me understand the code from the answer that I mentioned.

Alexander
  • 75
  • 2
  • 7

3 Answers3

0

For my case, it was quite simple, I just made a composable and called it in my MainActivity like this, in setContent:

 checkNotificationPolicyAccess(notificationManager, this)

Basically, if the permission is not granted, I show a Dialog.

@Composable
fun checkNotificationPolicyAccess(
    notificationManager: NotificationManager,
    context: Context
): Boolean {
    if (notificationManager.isNotificationPolicyAccessGranted) {
        return true
    } else {
        NotificationPolicyPermissionDialog(context)
    }
    return false
}
Code Poet
  • 6,222
  • 2
  • 29
  • 50
  • Not quite what I was looking for. I need to request a permission — a READ_SMS permission in my case — and then to handle a request code callback, so I can show either a list of SMS messages, if the permission granted, or a text saying that they are not supported without a permission. – Alexander Feb 02 '21 at 06:57
0

OK, I understood it.

You need to implement this composable and use it when you need to use a feature that needs the permissions: you pass in an array of permissions, a requestCode (any Int), and two lambdas with composables: onGranted, which is used when the permissions were granted, and onDenied composable in the other case.

@Composable
fun PermissionsRequest(
    permissions: Array<out String>,
    requestCode: Int,
    onGranted: @Composable () -> Unit,
    onDenied: @Composable () -> Unit,
    onDeniedPermanently: (@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.requestPermissions(requestCode, permissions))
    }

    when (permissionResult) {
        is PermissionResult.PermissionGranted -> onGranted()
        is PermissionResult.PermissionDenied -> onDenied()
        is PermissionResult.PermissionDeniedPermanently -> onDeniedPermanently?.invoke()
        is PermissionResult.ShowRational -> rational?.invoke()
        null -> awaitResult?.invoke()
    }
}

Also you need to implement an ambient. As I understand it, it is used to pass the value down the composables children. In our case AmbientPermissionHandler is going to be passed with its value — PermissionHandler — to the PermissionsRequest from Providers composable.

val AmbientPermissionHandler = ambientOf<PermissionHandler>()

The PermissionHandler implementation that would be passed to PermissionRequest composable as an AmbientPermissionHandler using Providers.

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

And then you use it like this:

class MainActivity : AppCompatActivity() {
    private val permissionHandler = PermissionHandler(this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Providers(
                AmbientPermissionHandler provides permissionHandler
            ) {
                PermissionsRequest(
                    permissions = arrayOf(Manifest.permission.READ_SMS),
                    requestCode = PERMISSION_REQUEST_CODE,
                    onGranted = { /* Here goes the composables when the permission is granted */ },
                    onDenied = { /* Is used when the permission is denied */ }
                )
            }
        }
    }
}

Initialize PermissionHandler in MainActivity and then provide it in Providers inside the setContent.

To use PermissionManager and LaunchedEffect you need those dependencies:

implementation 'com.sagar:coroutinespermission:2.0.3'
implementation 'androidx.compose.runtime:runtime:1.0.0-alpha11'

And thanks to 2jan222 for the sample code.

Alexander
  • 75
  • 2
  • 7
-1

you don't need any additional library for request permission

//define permission in composable fun
val getPermission = rememberLauncherForActivityResult( 
    ActivityResultContracts.RequestPermission()
) { isGranted ->
    if (isGranted) {
       //permission accepted do somthing
    } else {
       //permission not accepted show message
    }
}
//i used SideEffect to launch permission request when screen recomposed
//you can call it inside a button click without SideEffect
SideEffect {
    getPermission.launch(Manifest.permission.YOUR_PERMISSION_REQEUST)
}

and if you wanted to request multiple permission use this:

ActivityResultContracts.RequestMultiplePermissions()
Mahdi Zareei
  • 1,299
  • 11
  • 18