iT邦幫忙

2021 iThome 鐵人賽

DAY 18
1
Mobile Development

認真學 Compose - 對 Jetpack Compose 的問題與探索系列 第 18

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

  • 分享至 

  • xImage
  •  

今天大概會聊到的範圍

  • 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,主題滿大的,之後再獨立一篇分享吧!


上一篇
D17/ 我要用的 View 沒有支援 Compose 怎麼辦? - AndroidView
下一篇
D19/ 要權限的時後有 Launcher has not been initialized,怎麼辦? - SideEffect
系列文
認真學 Compose - 對 Jetpack Compose 的問題與探索30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言