如何使用 Jetpack Compose 请求权限?
How request permissions with Jetpack Compose?
Jetpack Compose View请求权限应该如何实现?我正在尝试使用 Jetpack Compose 实现访问相机的应用程序。我尝试了 中的示例,不幸的是示例不再适用于 dev06。
fun hasPermissions(context: Context) = PERMISSIONS_REQUIRED.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
}
}
private const val PERMISSIONS_REQUEST_CODE = 10
private val PERMISSIONS_REQUIRED = arrayOf(Manifest.permission.CAMERA)
@Composable
fun PermissionButton() {
val context = ContextAmbient.current
Button(onClick = {
if (!hasPermissions(context)) {
requestPermissions(
context as Activity,
PERMISSIONS_REQUIRED,
PERMISSIONS_REQUEST_CODE
)
}
}
) {}
}
fun hasPermissions(context: Context) = PERMISSIONS_REQUIRED.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
有点晚了,但这可能对我今天遇到的问题有所帮助:
使用 ContextAmbient.current
不能保证您拥有 activity 或片段,因此我创建了自己的环境来处理权限。
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 */}
用法:
@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()
}
}
PermissionHandler 的实现与依赖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))
}
}
}
如果您更喜欢回调,第二个函数也可以。
作为compose_version = '1.0.0-beta04'
和
implementation 'androidx.activity:activity-compose:1.3.0-alpha06'
您可以像这样简单地请求权限:
@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")
}
}
/**
* 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) }
}
}
查看 Google 伴奏者的 Jetpack Compose Permissions。
请记住,在撰写本文时,API 仍被认为是实验性的,使用时需要 @ExperimentalPermissionsApi
注释。
Google 有一个名为“Accompanist”的库。它有很多帮助库,其中之一是权限库。
检查:
图书馆:https://github.com/google/accompanist/
文档:https://google.github.io/accompanist/permissions/
示例:
build.gradle 文件中的设置:
repositories {
mavenCentral()
}
依赖项{
implementation "com.google.accompanist:accompanist-permissions:<latest_version>"
}
代码中的实现
@Composable
private fun FeatureThatRequiresCameraPermission() {
// Camera permission state
val cameraPermissionState = rememberPermissionState(
android.Manifest.permission.CAMERA
)
when (cameraPermissionState.status) {
// If the camera permission is granted, then show screen with the feature enabled
PermissionStatus.Granted -> {
Text("Camera permission Granted")
}
is PermissionStatus.Denied -> {
Column {
val textToShow = if (cameraPermissionState.status.shouldShowRationale) {
// If the user has denied the permission but the rationale can be shown,
// then gently explain why the app requires this permission
"The camera is important for this app. Please grant the permission."
} else {
// If it's the first time the user lands on this feature, or the user
// doesn't want to be asked again for this permission, explain that the
// permission is required
"Camera permission required for this feature to be available. " +
"Please grant the permission"
}
Text(textToShow)
Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
Text("Request permission")
}
}
}
}
}
别忘了补充
<uses-permission android:name="android.permission.CAMERA"/>
(请求相机许可时)到您的AndroidManifest.xml,否则在使用其他人提供的解决方案时,它可能会以权限被拒绝状态结束。
您可以请求多个权限。
class MainActivity : ComponentActivity() {
private val neededPermissions = arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
@OptIn(ExperimentalMaterialApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MfmTheme {
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestMultiplePermissions()
) { maps ->
val granted = maps.values.reduce { acc, next -> (acc && next) }
if (granted) {
// all permission granted
} else {
// Permission Denied: Do something
}
// You can check one by one
maps.forEach { entry ->
Log.i("Permission = ${entry.key}", "Enabled ${entry.value}")
}
}
val context = LocalContext.current
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background,
onClick = {
when {
hasPermissions(context, *neededPermissions) -> {
// All permissions granted
}
else -> {
// Request permissions
launcher.launch(neededPermissions)
}
}
}
) {
Greeting("Android")
}
}
}
}
private fun hasPermissions(context: Context, vararg permissions: String): Boolean =
permissions.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MfmTheme {
Greeting("Android")
}
}
Jetpack Compose View请求权限应该如何实现?我正在尝试使用 Jetpack Compose 实现访问相机的应用程序。我尝试了
fun hasPermissions(context: Context) = PERMISSIONS_REQUIRED.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
}
}
private const val PERMISSIONS_REQUEST_CODE = 10
private val PERMISSIONS_REQUIRED = arrayOf(Manifest.permission.CAMERA)
@Composable
fun PermissionButton() {
val context = ContextAmbient.current
Button(onClick = {
if (!hasPermissions(context)) {
requestPermissions(
context as Activity,
PERMISSIONS_REQUIRED,
PERMISSIONS_REQUEST_CODE
)
}
}
) {}
}
fun hasPermissions(context: Context) = PERMISSIONS_REQUIRED.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
有点晚了,但这可能对我今天遇到的问题有所帮助:
使用 ContextAmbient.current
不能保证您拥有 activity 或片段,因此我创建了自己的环境来处理权限。
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 */}
用法:
@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()
}
}
PermissionHandler 的实现与依赖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))
}
}
}
如果您更喜欢回调,第二个函数也可以。
作为compose_version = '1.0.0-beta04'
和
implementation 'androidx.activity:activity-compose:1.3.0-alpha06'
您可以像这样简单地请求权限:
@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")
}
}
/**
* 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) }
}
}
查看 Google 伴奏者的 Jetpack Compose Permissions。
请记住,在撰写本文时,API 仍被认为是实验性的,使用时需要 @ExperimentalPermissionsApi
注释。
Google 有一个名为“Accompanist”的库。它有很多帮助库,其中之一是权限库。
检查: 图书馆:https://github.com/google/accompanist/
文档:https://google.github.io/accompanist/permissions/
示例:
build.gradle 文件中的设置:
repositories {
mavenCentral()
}
依赖项{
implementation "com.google.accompanist:accompanist-permissions:<latest_version>"
}
代码中的实现
@Composable
private fun FeatureThatRequiresCameraPermission() {
// Camera permission state
val cameraPermissionState = rememberPermissionState(
android.Manifest.permission.CAMERA
)
when (cameraPermissionState.status) {
// If the camera permission is granted, then show screen with the feature enabled
PermissionStatus.Granted -> {
Text("Camera permission Granted")
}
is PermissionStatus.Denied -> {
Column {
val textToShow = if (cameraPermissionState.status.shouldShowRationale) {
// If the user has denied the permission but the rationale can be shown,
// then gently explain why the app requires this permission
"The camera is important for this app. Please grant the permission."
} else {
// If it's the first time the user lands on this feature, or the user
// doesn't want to be asked again for this permission, explain that the
// permission is required
"Camera permission required for this feature to be available. " +
"Please grant the permission"
}
Text(textToShow)
Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
Text("Request permission")
}
}
}
}
}
别忘了补充
<uses-permission android:name="android.permission.CAMERA"/>
(请求相机许可时)到您的AndroidManifest.xml,否则在使用其他人提供的解决方案时,它可能会以权限被拒绝状态结束。
您可以请求多个权限。
class MainActivity : ComponentActivity() {
private val neededPermissions = arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
@OptIn(ExperimentalMaterialApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MfmTheme {
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestMultiplePermissions()
) { maps ->
val granted = maps.values.reduce { acc, next -> (acc && next) }
if (granted) {
// all permission granted
} else {
// Permission Denied: Do something
}
// You can check one by one
maps.forEach { entry ->
Log.i("Permission = ${entry.key}", "Enabled ${entry.value}")
}
}
val context = LocalContext.current
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background,
onClick = {
when {
hasPermissions(context, *neededPermissions) -> {
// All permissions granted
}
else -> {
// Request permissions
launcher.launch(neededPermissions)
}
}
}
) {
Greeting("Android")
}
}
}
}
private fun hasPermissions(context: Context, vararg permissions: String): Boolean =
permissions.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MfmTheme {
Greeting("Android")
}
}