앱 권한 구현
권한을 학습하고 구현하는데 다름 꽤 시간을 사용했다.
아직 더 봐야하지만 문서만 보기 지쳐 구현을 시도해봤다.
모듈로 만들어 구현했다.
dependencies {
implementation 'com.github.sarang628:ComposePermissionTest:최신커밋'
}
기본 구현 프로세스를 코드로 정리해봤다.
when 구문에 있는 내용을 보면 대략적으로 프로세스를 이해할 수 있다.
권한 처리 절차는 따로 모아서 보고싶어 ViewModel에서 구현 했다.
@OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3Api::class)
@Composable
fun WorkFlowImpl(
viewModel: BestPracticeViewModel = BestPracticeViewModel(),
permission : String = Manifest.permission.ACCESS_FINE_LOCATION
) {
var timeDiff : Long by remember { mutableStateOf(0L) } // 영구 권한 거부 상태 체크를 위한 시간
val requestPermission = rememberPermissionState(permission, { viewModel.permissionResult(it, System.currentTimeMillis() - timeDiff); })
val state = viewModel.state
var stateTxt by remember { mutableStateOf("RequestPermission") }
when (state) {
InitialPermissionCheck /* 최초 권한 체크 */ -> { viewModel.initialPermissionCheck(requestPermission.status.isGranted) }
RecognizeToUser /* UX에 권한을 필요로 하는 정보 인지 시키기 */-> { DescribePermissionDialog(onYes = { viewModel.yesInRecognizeUser() }, onNo = { viewModel.noInRecognizeUser() }) }
CheckRational /* rational 여부 확인 */-> { viewModel.checkRational(requestPermission.status.shouldShowRationale) }
DeniedPermission /* 권한 거부 */-> { stateTxt = "권한을 거부함." }
GrantedPermission /* 사용자가 권한을 허가했다면, 자원 접근 가능 */-> { stateTxt = "권한을 허용함." }
RequestPermission /* 런타임 권한 요청하기 */ -> { LaunchedEffect(state == RequestPermission) { requestPermission.launchPermissionRequest(); timeDiff = System.currentTimeMillis() } }
SuggestSystemSetting /* 권한 거부 상태에서 요청 시 */ -> { MoveSystemSettingDialog(onMove = { viewModel.onMoveInSystemDialog() }, onDeny = {viewModel.noInSystemDialog()}) }
ShowRationale /* rationale을 표시 */ -> { RationaleDialog({ viewModel.yesRationale() }, {viewModel.noRationale()}) }
}
Column {
Text(state.toString().split("$")[1].split("@")[0])
MyLocation(hasPermission = requestPermission.status.isGranted, 0, onRequestPermission = {
viewModel.request()
})
}
}
1. 최초 권한 체크
권한 유무를 체크하여 5.DeniedPermission 또는 6.GrantedPermission 으로 상태를 변경
InitialPermissionCheck /* 최초 권한 체크 */ -> {
viewModel.initialPermissionCheck(requestPermission.status.isGranted)
}
이벤트에 대한 뷰모델 처리 이다.
/**
* 최초 권한 체크
* @param isGranted 권한 허용 여부
* @return GrantedPermission(허용 시) or DeniedPermission(그 외)
*/
fun initialPermissionCheck(isGranted: Boolean) {
viewModelScope.launch {
delay(1)
state = if (isGranted) GrantedPermission else DeniedPermission
}
}
2. UX에 권한을 필요로 하는 정보 인지 시키기
화면 다이얼로그는 아래같이 처리했다.
RecognizeToUser /* UX에 권한을 필요로 하는 정보 인지 시키기 */-> {
DescribePermissionDialog(onYes = { viewModel.yesInRecognizeUser() }, onNo = { viewModel.noInRecognizeUser() })
}
뷰모델에서 다이얼로그 이벤트 따른 다음순서이다. (이렇게 단순한데 로직을 나눌필요 있을까 싶지만. 모르겠다. 이렇게 하고싶었다.)
/** 사용자 알림 화면에서 Yes */
fun yesInRecognizeUser() { state = CheckRationale }
/** 사용자 알림 화면에서 No */
fun noInRecognizeUser() { state = InitialPermissionCheck }
3. Rational 여부 확인
권한을 요청하면 요청 전 Rationale(권한이 필요한 이유) 보여줘야 하는지 체크한다.
CheckRational /* rational 여부 확인 */-> { viewModel.checkRational(requestPermission.status.shouldShowRationale) }
ShowRationale /* rationale을 표시 */ -> { RationaleDialog({ viewModel.yesRationale() }, {viewModel.noRationale()}) }
4. 권한 요청하기
timeDiff는 권한을 2번 거부하면, 요청 하더라도 바로 거부로 떨어져 시간을 체크해 영구 거부 여부를 확인 용도이다.
RequestPermission /* 런타임 권한 요청하기 */ -> { LaunchedEffect(state == RequestPermission) { requestPermission.launchPermissionRequest(); timeDiff = System.currentTimeMillis() } }
5. 시스템 권한 화면 이동
2회 이상 권한을 거부하면, 다음 권한 요청시 SuggestSystemSetting 상태로 변경 됨.
이 상태에서 아래와 같은 다이얼로그를 띄워준다.
화면 이동 여부 사용자 액션에 대해 이벤트를 설정 해줘야 함. viewModel.onMoveInSystemDialog(), viewModel.noInSystemDialog()
SuggestSystemSetting /* 권한 거부 상태에서 요청 시 */ -> { MoveSystemSettingDialog(onMove = { viewModel.onMoveInSystemDialog() }, onDeny = {viewModel.noInSystemDialog()}) }
6. (추가) onStart 시 권한 다시 체크하기
// 앱이 포그라운드로 복귀했을 때 실행
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) {
viewModel.onStart()
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
어려운듯. 할만 한 듯. 까다로운 권한 체크 프로세스 이다. private dashboard나 앱 권한 페이지에 처리하는 기능도 있어 이 부분도 추후 구현해보겠다.
https://github.com/sarang628/ComposePermissionTest
GitHub - sarang628/ComposePermissionTest
Contribute to sarang628/ComposePermissionTest development by creating an account on GitHub.
github.com