[Android] Compose에서 권한 묻기(com.google.accompanist:accompanist-permissions)
사용자의 위치를 가져와야 하는 일이 생겨서 라이브러리를 사용해서 권한을 묻는 기능을 만들어보려고 한다.
공식 문서를 먼저 확인했다: 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