Accompanist库的launchPermission函数并没有提供回调函数的接口。但我们可以使用Kotlin协程中提供的suspendCancellableCoroutine函数来实现自定义的回调函数。具体实现方式如下:
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
/**
* Launches a system permission request for the specified [permission] and suspends
* until the user has granted or denied the permission. The [rationale] function is called
* if the user has previously denied the permission and [shouldShowRationale] is true.
* Returns true if the permission is granted, false otherwise.
*/
suspend fun launchPermission(
permission: String,
rationale: (suspend () -> Unit)? = null,
shouldShowRationale: (String) -> Boolean = { true }
): Boolean {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val requestPermissionLauncher = remember(context) {
context.activityResultRegistry.register(
"request_$permission",
lifecycleOwner,
ActivityResultContracts.RequestPermission()
) { result ->
/* no-op */
}
}
val coroutineScope = rememberCoroutineScope()
return suspendCancellableCoroutine { continuation ->
val permissionStateFlow = context.checkSelfPermission(permission)
.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
val permissionState = permissionStateFlow.first()
if (permissionState == android.content.pm.PackageManager.PERMISSION_GRANTED) {
continuation.resume(true)
} else if (shouldShowRationale(permission)) {
coroutineScope.launch {
rationale?.invoke()
continuation.resume(false)
}
} else {
val permissionRequest = permissionRequest { continuation.resume(it) }
requestPermissionLauncher.launch(permission)
continuation.invokeOnCancellation {
if (it is CancellationException) {
permissionRequest.cancel()
}
}
}
}
}
``