D18/ 怎麽在 Compose 中取得 Permission? - rememberLauncherForActivityResult

今天大概会聊到的范围

  • rememberLauncherForActivityResult

上一篇我学到可以透过 AndroidView 中将 CameraX 的 PreviewView 加入 Compose 中,要显示相机的画面,还需要取得 User 的 Permission。所今天想来研究一下如果我的 Compose 元素想要与 Permission  互动应该怎麽处理。

首先,取得 permission 并不会太复杂:

//  checkPermission
private fun checkPermissionsGranted(context: Context) = REQUIRED_PERMISSIONS.all {
    ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

取得 permission 时会需要 Context,而在 Compose 中要取得 Context 可以透过 LocalContext.current 取得

@Composable
fun CameraScreen() {
    
    // 取得 context
    val context = LocalContext.current
    
    // 检查完 permission 後将答案存在 remember 中
    var hasPermission by remember {
        mutableStateOf(checkPermissionsGranted(context))
    }
    
    if (hasPermission) {
        CameraView()
    } else {
        LoadingView()
    }
}

startActivityForResult in Compose

接下来,我们需要透过 startActivityForResult 向 User 请求 permission。在 Compose 中,可以透过 rememberLauncherForActivityResult 建立一个 launcher。这个 launcher 中的 callback 我们可以对 result 做处理(这边我们将 result 存放回 state )

var hasPermission by remember {  // ... 

val permissionRequester = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
   
    hasPermission = isGranted
}

permissionRequester 并不会立刻起作用,而是要在需要取得的时候触发:

    if (hasPermission) {
        CameraView()
    } else {
        LoadingView(modifier = Modifier.clickable { permissionRequester.launch(Manifest.permission.CAMERA) })
    }

使用rememberLauncherForActivityResult 时,需要提供一个 contract 和一个 callback

@Composable
public fun <I, O> rememberLauncherForActivityResult(
    contract: ActivityResultContract<I, O>,
    onResult: (O) -> Unit
): ManagedActivityResultLauncher<I, O> {

ActivityResultContract 各种 startActivityForResult 的流程,例如 ActivityResultContract.RequestPermission 可以取得一个 Permission ,另外还有 ActivityResultContract.RequestMultiplePermissions 可以一次请求多种权限。当今天内建的流程不符合需求时,还可以使用 ActivityResultContract.StartIntentSenderForResult 自订

class RequestPermission extends ActivityResultContract<String, Boolean>

ActivityResultContract 会需要一个 input 和一个 output 的 type,以 RequestMultiplePermissions 为例, input 就是一个 String ( permission key),output 则是 Boolean 代表是否接受权限。output 的资料会在 callback ( onResult ) 中出现,input 则是在 launch 时提供


完成以上,就可以在 user 点击 LoadingView 後跳出权限取得的 Dialog。但是如果今天要自动 launch 则会出现 Launcher has not been initialized 的错误。这个原因会需要提到 SideEffect,主题满大的,之後再独立一篇分享吧!


<<:  Day18 Vue元件的宣告与注册

>>:  30天学会C语言: Day 16-你可能会用到的函式

个人or团队这回事(上)

讲到团队(Team),就会先讲到团体(Group)这个字,谈团队之前,其实要先这样想:根本没有团队这...

30天学会C语言: Day 27-指标当参数

函式没办法使用其他函式中的变数 #include <stdio.h> #include ...

Vaadin 汉堡选单 - AppLayout - day16

Web 应用程序选单多样化,早期最常见的多半树状选单,直至手机问世後汉堡选单(hamburger m...

Day 28 - XState in React (着重: local state)

前面介绍许多 State Machine 及 XState 的功能,由於篇幅不多了,今天想跟大家先快...

[Angular] Day16. Writing structural directives

在上一章中介绍了如何建立客制化的 attribute directive 与使用,而本章将会介绍如何...