코딩 일기장/Android(Kotlin)

[Android] Compose에서 권한 묻기(com.google.accompanist:accompanist-permissions)

minWachya 2025. 6. 27. 21:37
반응형

사용자의 위치를 가져와야 하는 일이 생겨서 라이브러리를 사용해서 권한을 묻는 기능을 만들어보려고 한다.

공식 문서를 먼저 확인했다: https://google.github.io/accompanist/permissions/

 

만들려는 것은 다음과 같다.

- 필요한 권한과 권한이 필요한 이유를 보여주는 화면

- "권한 설정하기" 버튼을 눌러 관련 권한(나의 경우 위치) 설정 다이얼로그 띄우기

- 권한 허용 시 다음 화면으로 이동

- 권한 거절 시 직접 권한 설정 화면으로 이동하도록 유도


1. 라이브러리 설치

toml에 버전 설정해준다. 최신 버전은 위에 있는 공식 문서 링크 확인!!

[versions]
//...
permission = "0.37.3"

[libraries]
//...
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "permission" }

gradle에 이렇게 추가해주고 또 싱크~

// Permission
implementation(libs.accompanist.permissions)

 

2. Manifest에 권한 명시

나는 위치 정보 관련 권한만 필요해서 일단 이렇게 추가했다.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

3. Code

주석에 대한 설명은 밑에 있다.

// 1
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionRequestScreen(modifier: Modifier) {
	// 2
    val permissionState = rememberMultiplePermissionsState(
        listOf(
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
        ),
    )

	// 3-1
    val permissionList = listOf(
        PermissionInfo(
            titleRes = R.string.fine_location_title,
            descriptionRes = R.string.fine_location_description,
            imageVector = Icons.Default.LocationOn
        )
    )

    Surface(
        color = MaterialTheme.colorScheme.surface
    ) {
        Column(
            modifier = modifier
                .fillMaxWidth()
                .animateContentSize()
                .padding(vertical = 24.dp, horizontal = 16.dp),
        ) {
            Text(
                text = "정확한 날씨 정보를 위해\n아래의 권한을 허용해주세요.",
                modifier = modifier.padding(vertical = 20.dp, horizontal = 20.dp)
            )
            // 3-2
            LazyColumn(
                modifier = modifier
                    .weight(1F)
            ) {
                items(permissionList) { permissionInfo ->
                    PermissionItem(permissionInfo = permissionInfo)
                }
            }

			// 4: 권한 거부 시 로직: 설정 화면으로 이동
            if (permissionState.shouldShowRationale) {
                Text(
                    text = "정확한 날씨 정보를 얻기 위해 위치 정보가 꼭 필요합니다.",
                    color = MaterialTheme.colorScheme.onErrorContainer
                )
                val context = LocalContext.current
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                    data = Uri.fromParts("package", context.packageName, null)
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                }

                Button(
                    modifier = modifier
                        .padding(vertical = 20.dp)
                        .fillMaxWidth(),
                    onClick = { context.startActivity(intent) }
                ) {
                    Text(text = "직접 권한 설정하기")
                }
            }
            // 5: 권한 요청 로직
            else {
                Button(
                    modifier = modifier
                        .padding(vertical = 20.dp)
                        .fillMaxWidth(),
                    onClick = { permissionState.launchMultiplePermissionRequest() }
                ) {
                    Text(text = "권한 설정하기")
                }
            }
        }
    }
}

 

// 1: @OptIn(ExperimentalPermissionsApi::class)

공식 문서에 들어가보면 바로 이런 Warning이 뜬다.

The permission APIs are currently experimental and they could change at any time. All of the APIs are marked with the @ExperimentalPermissionsApi annotation.

이 permission API는 실험적이라 언제든지 변경될 수 있어서 @ExperimentalPermissionApi 어노테이션을 표시했다는 내용인데, 우리도 이 api를 사용할 것이기 때문에 클래스명 위에 위 어노테이션을 설정해줬다.

 

// 2: 필요한 권한의 허용 여부를 저장하고 있는 배열

Compose에서는 이 권한을 허용했는지 거부했는지의 상태를 rememberPermissionsState를 통해 관리할 수 있다. 이건 권한이 하나일 때 사용하는 거고 권한 여러 개의 상태를 관리하기 위해서 rememberMultiplePermissionsState를 사용한다.

나는 나중에 묻는 권한이 추가될 때를 대비해서 rememberMultiplePermissionsState를 사용했다.

 

// 3-1, 3-2: 필요 권한을 설정하는 UI

말 그대로 필요한 권한의 목록을 만들고 해당 목록을 PermissionItem으로 만들어서 LazyColumn을 통해 보여지는 부분이다.

 

// 4, 5: 권한 상태에 따른 로직

rememberMultiplePermissionsState를 통해 관리하고 있는 권한 상태가 변할 때마다 다른 로직을 정할 수 있다.


라이브러리 덕분에 어렵지 않게 구현할 수 있었다.

그리고 찾아보니 안드로이드에서도 Compose로 권한 제공하는 방법을 강의 형태로 제공하고 있어서(아래 참고) 초보자도 더 쉽게 코드 짤 수 있을 거 같다.

 

참고

 

Jetpack Compose의 고급 상태 및 부작용  |  Android Developers

이 Codelab에서는 Jetpack Compose의 상태 및 부수 효과에 관한 고급 개념을 알아봅니다. 복잡한 스테이트풀(Stateful) 컴포저블의 상태 홀더를 만드는 방법, Compose 코드에서 코루틴을 만들고 정지 함수를

developer.android.com

 

 

platform-samples/samples/location/src/main/java/com/example/platform/location/permission/LocationPermissionsScreen.kt at main ·

A collection of samples of different Android OS platform APIs. - android/platform-samples

github.com

 

[Android]Jetpack Compose & Accompanist Permissions를 활용한 권한 요청 플로우

Jetpack Compose와 Accompanist Permissions를 활용하여 안드로이드 앱에서 권한 요청 화면을 구성하기

velog.io

 

반응형