[Android] 권한 요청 중 Rationale 활용하기 with shouldShowRequestPermissionRationale

Kame·2025년 11월 3일

Android

목록 보기
7/9
post-thumbnail

들어가며

??? : Rationale이 뭐야?

안드로이드 앱을 개발하다 보면 권한 처리 는 피할 수 없는 과정입니다.

특히 Android 6.0 (Marshmallow, API 23) 부터는 위험 권한(Dangerous Permissions)을 사용하기 위해 런타임(Runtime)에 사용자로부터 명시적으로 권한을 부여받아야 합니다. 즉, 위치나 카메라 등 사용자의 민감한 정보 또는 하드웨어에 접근하려면 반드시 권한 요청 절차를 거쳐야 합니다. 또한 이 과정에서 버전별 권한 정책 차이, 사용자의 거부/허용 상태에 따른 분기 처리 등 다양한 시나리오도 고려해야 합니다.

이 때 활용될 수 있는 것이 Rationale입니다. 이 글에서는 Rationale을 활용하는 이유, 관련 메서드의 동작 방식과 한계 그리고 그 해결 방법을 알아보겠습니다.


Rationale

안드로이드 측에서는 특정 상황에서 교육용 UI를 통해 해당 권한이 필요한 이유(Rationale)를 사용자에게 설명하는 것을 권장합니다. 이것을 다이얼로그를 비롯한 여러 종류의 UI 컴포넌트로 사용자에게 알릴 수 있습니다. 아래 예시는 네이버 앱에 ‘위치’ 권한을 부여하지 않은 상태로 처음 진입하였을 때의 모습입니다.

Rationale을 보여주고자 하는 상황은 구현하는 프로젝트 혹은 기능의 성격에 따라 다를 수 있습니다. 다만 안드로이드 공식문서에 따르면 다음과 같은 상황과 순서로 요청하는 방식을 제시하고 있음을 알 수 있습니다.

  • 앱에서 사용자가 필요로 하는 기능에 접근
  • 유저가 권한을 허용하지 않았다는 전제 하에, 설명을 보여줘야 한다면
    • 먼저 유저에게 해당 권한이 필요한 이유를 설명(= Rationale, 즉 교육용 UI 표출)
    • 이후 시스템 다이얼로그를 보여주며 유저에게 권한 요청

어떤 조건에서 보여주어야 할까?

이 권장 사항에서 다음과 같은 의문이 생길 수 있습니다.

설명을 보여주어야 하는 경우는 어떤 경우인가?

이 질문의 답을 찾기 위해서는 ActivityCompat의 멤버 중 하나인 shouldShowRequestPermissionRationale() 메서드를 살펴볼 필요가 있습니다.

shouldShowRequestPermissionRationale()

쉽게 말해, 이 함수는 권한 요청 흐름에서 플로우차트의 5a의 여부(Rationale을 보여줄지)를 결정합니다. 함수의 반환값이 true라면 사용자에게 권한이 필요한 이유를 설명하는 UI(Rationale)를 보여주어야 하고, false라면 곧바로 시스템 권한 다이얼로그를 띄우면 됩니다.

해당 함수의 반환값은 다음 기준에 따라 결정됩니다.

  • true
    • 권한이 아직 허용되지 않았을 때, 사용자가 시스템 권한 다이얼로그에서 ‘한 번’ 거절한 이력이 있을 경우
    • 과거에 권한이 허용되어 있었던 경우, 사용자가 설정 등 다른 경로에서 직접 권한을 거부한 경우 (횟수 제한 없음)
  • false
    • (당연하지만) 이미 권한이 허용되어 있는 경우
    • 사용자가 권한을 한 번도 요청받은 적이 없는 최초 요청 상황
    • 사용자가 시스템 다이얼로그 상에서 권한을 두 번 이상 거부한 경우 (Android 11 이상)
    • “다시 묻지 않기”를 선택한 경우 (Android 10 이하)

내부 구현

shouldShowRequestPermissionRationale()의 반환값은 시스템 내부의 권한 플래그 상태에 따라 결정됩니다. AOSP의 PermissionManagerService의 내부 구현에 의해 다음과 같은 조건으로 구체화됩니다.

@Override
public boolean shouldShowRequestPermissionRationale(
		String permName,
		String packageName, 
		int userId
) {
    // ...
    
    // 권한 허용이 되어 있는 경우 false 반환
    if (checkPermission(permName, packageName, userId)
        == PackageManager.PERMISSION_GRANTED) {
        return false;
    }

		// FLAG_PERMISSON_USER_FIXED
		// 유저가 시스템 다이얼로그 상에서 2번 거절하거나 '다시 묻지 않음'을 선택했을 때 설정됨
    final int flags = getPermissionFlagsInternal(permName, packageName, callingUid, userId);
    final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                          | PackageManager.FLAG_PERMISSION_POLICY_FIXED
                          | PackageManager.FLAG_PERMISSION_USER_FIXED;
                          
    if ((flags & fixedFlags) != 0) {
        return false;
    }
    
    // ...

    // 이외 상황에서 유저가 한 번이라고 권한을 명시적으로 허용 혹은 거부했을 때 true 반환
    return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
}

표의 내용을 요약하면 다음과 같습니다.

상황FLAG_PERMISSION_USER_FIXEDFLAG_PERMISSION_USER_SETshouldShowRequestPermissionRationale()설명
처음 요청false아직 사용자가 응답하지 않음
1번 거부trueRationale 표시 권장 시점
2번 거부 (Android 11+)falsefixedFlags 체크에서 걸림
"다시 묻지 않음" 선택 (Android 10 이하)falsefixedFlags 체크에서 걸림
권한 허용됨--false첫 번째 체크에서 반환

공식문서를 살펴보면, 곳곳에 권한 관련 동작이 사용자의 앱 활용을 방해하지 않아야 한다는 문구를 확인할 수 있습니다. 안드로이드 측에서 가지고 있는 권한 설정 관련 철학을 엿볼 수 있습니다.

사용자 인터페이스를 차단하지 않습니다. 즉, 사용자가 앱을 계속 사용하는 것을 막는 전체 화면 경고 메시지를 표시하지 않습니다.

사용자를 차단하지 않습니다. 교육용 UI 흐름(예: 권한 요청의 근거를 설명하는 흐름)을 취소하는 옵션을 항상 제공합니다.

동시에 앱은 권한을 거부하겠다는 사용자의 결정을 존중해야 합니다. Android 11(API 수준 30)부터 사용자가 앱이 기기에 설치된 전체 기간 동안 특정 권한에 관해 거부를 두 번 이상 탭하면 앱에서 그 권한을 다시 요청하는 경우 사용자에게 시스템 권한 대화상자가 표시되지 않습니다.


현실에서는?

안드로이드 권한 가이드라인에서는 shouldShowRequestPermissionRationale()FLAG_PERMISSION_USER_FIXED, FLAG_PERMISSION_USER_SET 등의 상태를 기반으로, 사용자가 권한 요청을 거부했을 때 적절한 안내를 하도록 권장하고 있습니다. 하지만 실제 서비스에서는 몇 가지 현실적인 고민이 발생합니다.

  • 반드시 먼저 설명을 보여주고 권한을 요청해야 하는가?
  • 반드시 2번 이상 거절했을 때 사용자에게 권한 허용을 유도하지 않아야 하는가?

이러한 이유로, 많은 프로젝트에서는 서비스 특성에 맞춰 가이드라인을 그대로 따르기보다는 유연하게 대응하고 있습니다. 실제로 정말 중요한 기능이라면, 사용자가 2번 이상 권한을 허용하지 않았을 때, 시스템 다이얼로그는 더 이상 보여주지 못하더라도 설정 화면으로 이동할 수 있는 버튼이 포함된 커스텀 다이얼로그를 표출하여 사용자가 권한을 허용하도록 유도할 수도 있습니다.

예를 들어, 안드로이드 프레임워크에서 제공하는 권한 관련 메서드만 활용하기 보다는, SharedPreference나 DataStore를 활용하여 사용자의 권한 거부 횟수나 안내 표시 여부를 기기에 기록하면, 상황에 맞는 안내를 제공할 수 있습니다.

결국, 권한 요청 전략은 단순히 가이드라인을 따르는 것을 넘어, 사용자 경험과 서비스 특성에 맞게 설계하는 것이 중요합니다. 사용자가 권한 요청으로 불편을 겪지 않도록 하면서도, 앱의 핵심 기능을 안전하게 제공할 수 있어야 할 것입니다.


마치며

안드로이드의 권한 처리 관련 메서드 중 shouldShowRequestPermissionRationale()은 안드로이드의 철학이 반영된 유용한 메서드이지만, 모든 서비스의 요구사항을 완벽하게 충족시키기는 어려울 수 있습니다. 따라서 서비스의 특성과 사용자의 맥락을 고려하여 적절한 권한 요청 전략을 수립해야 할 것입니다.

참고 자료

https://developer.android.com/training/permissions/requesting?hl=ko

https://android.googlesource.com/platform/prebuilts/fullsdk/sources/android-30/%2B/refs/heads/main/com/android/server/pm/permission/PermissionManagerService.java

profile
Software Engineer

0개의 댓글