shouldShowRequestPermissionRationale in Android — 개념, 표시 로직 및 구현

저자: IT Sectr 게시일: 2026-05-20 읽는 시간: 8 분

shouldShowRequestPermissionRationale는 위험한 권한을 요청하기 전에 사용자에게 설명을 표시해야 하는지 여부를 개발자에게 알려주는 Android API 메서드입니다. Android Developer Reference, 2024에 따르면, 이 메서드는 사용자가 이전에 요청을 거부했지만 Never Ask Again 플래그를 설정하지 않은 경우 true를 반환합니다. 이는 런타임 권한으로 작업할 때 정중한 UX를 구축하기 위한 핵심 도구입니다.

핵심 사항

  • shouldShowRequestPermissionRationale — 권한 요청 전에 설명을 표시해야 하는지 결정하는 메서드입니다.
  • Never Ask Again이 활성화되지 않은 경우 사용자의 첫 거부 후 true를 반환합니다.
  • 권한이 요청된 적이 없거나, 부여되었거나, 영구적으로 차단된 경우 false를 반환합니다.
  • 특정 권한이 필요한 이유를 설명하는 사용자 지정 대화상자를 표시하는 데 사용됩니다.
  • never ask again(false + denied)인 경우 사용자를 설정으로 리디렉션해야 합니다.

shouldShowRequestPermissionRationale란

shouldShowRequestPermissionRationale는 Android의 Activity 및 Fragment 클래스의 메서드로, 호환성을 위해 ActivityCompat을 통해 사용할 수 있습니다. 권한 이름을 받아 다시 요청하기 전에 사용자에게 추가 설명을 표시해야 하는지 나타내는 Boolean을 반환합니다. 이 메서드는 Android 6.0 Marshmallow의 런타임 권한 모델과 함께 등장했습니다.

설명 메커니즘은 권한 대화상자와의 사용자 상호작용 기록 추적을 기반으로 합니다. 시스템은 사용자가 이전에 요청을 거부했는지 기억합니다. Never Ask Again 플래그를 설정하지 않고 거부가 발생한 경우 shouldShowRequestPermissionRationale는 true를 반환합니다. 이는 개발자에게 보내는 신호입니다. 사용자가 권한이 필요한 이유를 이해하지 못하며 추가 설명이 필요합니다. Google Material Design 가이드라인에 따르면, 첫 거부 후 설명 대화상자를 표시하면 권한 재부여 확률이 35퍼센트 증가합니다.

반환 값의 의미를 이해하는 것이 중요합니다. true는 대화상자를 표시하는 것이 의미 있음을 나타내고, false는 대화상자가 필요하지 않거나(권한이 이미 부여되었거나 요청된 적이 없음) 쓸모없음(Never Ask Again 활성)을 나타냅니다. 이 메서드는 대화상자가 표시된다는 보장이 아니라 권장 사항을 제공할 뿐입니다. 개발자가 응답으로 표시할 UI를 결정합니다.

메서드 도입 시기

shouldShowRequestPermissionRationale는 API 레벨 23에서 런타임 권한을 위한 메서드 그룹과 함께 도입되었습니다. Android 6.0 이전에는 모든 권한이 설치 시 요청되었으며 설명 메커니즘이 필요하지 않았습니다. 사용자는 목록 전체를 한 번에 수락하거나 거부했습니다. 런타임 모델은 사용자가 컨텍스트를 이해하지 못한 채 요청을 거부할 수 있게 했으며, 바로 이것이 설명이 필요한 이유입니다.

shouldShowRequestPermissionRationale 작동 방식

메서드 로직은 다음과 같이 작동합니다. 특정 권한에 대한 requestPermissions의 첫 번째 호출에서 shouldShowRequestPermissionRationale는 false를 반환합니다. 사용자가 아직 대화상자를 접하지 않았습니다. 사용자가 요청을 거부(Deny 누름)하면 메서드가 true를 반환하기 시작합니다. Never Ask Again 플래그와 함께 반복 거부된 후 메서드는 false를 반환합니다.

전체 상태 표:

상태shouldShowRationalecheckSelfPermission개발자 조치
요청되지 않음falseDENIED시스템 대화상자 표시
부여됨falseGRANTED기능 실행
첫 거부trueDENIED설명 표시 후 시스템 대화상자
Never Ask AgainfalseDENIED설정으로 리디렉션

shouldShowRequestPermissionRationale = false와 checkSelfPermission = DENIED의 조합은 처리하기 가장 어려운 경우입니다. 이는 권한이 요청된 적이 없거나 Never Ask Again이 설정되었음을 의미합니다. 개발자는 이 두 상태를 구별해야 합니다. 유일한 방법은 SharedPreferences 또는 SavedStateHandle을 사용하여 isFirstRequest 플래그를 저장하는 것입니다. 첫 번째 요청에서 플래그를 설정하고, 플래그가 이미 true인 상태에서 shouldShowRationale가 false를 반환하면 Never Ask Again을 의미합니다.

상태 재설정

shouldShowRequestPermissionRationale는 사용자가 앱을 제거하고 다시 설치하거나, 앱 데이터를 지우거나, 권한 설정을 재설정하면 재설정됩니다. 재설치 후 메서드는 첫 번째 요청에 대해 다시 false를 반환합니다. 시스템 업데이트 및 Android 버전 변경은 기록을 재설정하지 않습니다. 기록은 앱 데이터에 저장됩니다.

설명 대화상자 구현

적절한 설명 구현에는 세 가지 구성 요소가 포함됩니다. 거부 후 shouldShowRequestPermissionRationale 확인, 설명이 포함된 사용자 지정 대화상자 표시, 사용자의 긍정적 응답 후 requestPermissions 다시 호출입니다. 대화상자는 간결하고 구체적이어야 하며 앱에 이 특정 권한이 필요한 이유를 설명해야 합니다.

kotlin
private fun requestLocationWithRationale() {
    val permission = Manifest.permission.ACCESS_FINE_LOCATION

    when {
        ContextCompat.checkSelfPermission(
            this, permission
        ) == PackageManager.PERMISSION_GRANTED -> {
            startLocationTracking()
        }
        ActivityCompat.shouldShowRequestPermissionRationale(
            this, permission
        ) -> {
            showRationaleDialog(permission)
        }
        else -> {
            requestPermissionLauncher.launch(permission)
        }
    }
}

private fun showRationaleDialog(
    permission: String
) {
    AlertDialog.Builder(this)
        .setTitle("위치 접근이 필요한 이유")
        .setMessage(
            "앱이 지도에서 장소를 표시하기 위해 위치를 사용합니다" +
            ". 이 권한이 없으면" +
            "기능이 작동하지 않습니다."
        )
        .setPositiveButton("허용") { _, _ ->
            requestPermissionLauncher.launch(permission)
        }
        .setNegativeButton("취소", null)
        .show()
}

설명을 위한 UI 패턴

Material Design 모범 사례에서는 설명에 모달 대화상자 대신 바텀 시트나 인라인 배너를 사용하는 것이 좋습니다. 바텀 시트는 덜 방해가 되며 사용자에게 컨텍스트를 제공합니다. 화면의 인라인 요소(예: 설명과 허용 버튼이 있는 카드)는 권한 없이 기능을 사용할 수 없음을 보여주지만 나머지 인터페이스를 차단하지는 않습니다.

설명 현지화

설명 텍스트는 현지화되어 특정 기능에 맞게 조정되어야 합니다. “앱 작동에 필요합니다”와 같은 일반적인 문구를 사용하지 마십시오. 구체적으로 명시하십시오: “사용자 근처의 날씨를 표시하려면” 또는 “사진을 갤러리에 저장하려면.” 구체적인 설명은 Google UX 연구에 따르면 권한 부여 가능성을 50퍼센트까지 높입니다.

설명과 Never Ask Again 비교

차이점 shouldShowRequestPermissionRationale = true(첫 거부)와 DENIED가 있는 false(Never Ask Again)는 권한 처리의 핵심 포인트입니다. 첫 번째 경우 사용자는 망설였으며 추가 설명이 액세스 권한을 부여하도록 설득할 수 있습니다. 두 번째 경우 사용자는 최종 결정을 내렸으며 시스템 대화상자를 반복하면 짜증만 유발할 것입니다.

거부 후 처리 알고리즘은 다음과 같아야 합니다:

  • 요청 콜백에서 DENIED 결과 가져오기
  • shouldShowRequestPermissionRationale 호출
  • true인 경우 — 재시도 버튼이 있는 사용자 지정 설명 대화상자 표시
  • false인 경우 — 설정 열기 버튼이 있는 대화상자 표시

순서를 혼동하지 않는 것이 중요합니다. 먼저 shouldShowRequestPermissionRationale를 확인하고 checkSelfPermission이 아닙니다. checkSelfPermission은 두 경우 모두 DENIED를 반환합니다. shouldShowRequestPermissionRationale만 첫 거부와 Never Ask Again을 구별합니다. “첫 번째 요청이 있었음” 플래그를 저장하려면 SavedStateHandle 또는 SharedPreferences를 사용하십시오. 이것이 “요청된 적 없음”과 “차단됨”을 구별하는 유일한 신뢰할 수 있는 방법입니다.

설명 표시 모범 사례

설명을 표시하는 것은 한 번만 하십시오. 사용자가 설명을 본 후 요청을 다시 거부하면 설명을 다시 표시하지 마십시오. 즉시 설정 열기를 제안합니다. 설명을 반복적으로 표시하면 성가신 것으로 인식되어 앱 평점이 낮아집니다. 최적의 시나리오: 요청 — 거부 — 설명 — 재요청 — 거부 — 설정.

첫 번째 요청 전에 설명을 표시하지 마십시오. 일부 개발자는 “사용자가 이해해야 한다’고 주장하며 첫 번째 대화상자 전에 설명을 잘못 표시합니다. 이는 UX를 저하시킵니다. 사용자는 하나 대신 두 개의 대화상자를 연속으로 보게 됩니다. Google은 시스템 대화상자를 즉시 표시하고 설명은 거부 후에만 표시할 것을 권장합니다.

기능이 실제로 필요할 때에 연결된 컨텍스트 기반 설명을 사용하십시오. 앱 시작 시 모든 권한을 요청하지 마십시오. 이것은 가장 낮은 허용률을 보입니다. 사용자가 “사진 촬영” 버튼을 탭할 때 카메라를 요청하고 지도를 열 때 위치를 요청하십시오. 컨텍스트 기반 요청과 설명을 결합하면 시작 시 요청의 30퍼센트에 비해 허용률이 80퍼센트까지 증가합니다.

설명 시나리오 테스트

shouldShowRequestPermissionRationale 테스트에서는 표의 네 가지 상태(요청되지 않음, 부여됨, 거부됨, Never Ask Again)를 확인해야 합니다. 단위 테스트에서는 구성 가능한 shouldShowRationale 동작이 있는 FakePermissionHandler를 사용합니다. 계측 테스트에서는 대화상자 응답 에뮬레이션과 함께 UiAutomator 또는 Espresso를 사용합니다.

kotlin
class RationaleViewModelTest {

    private val handler = FakePermissionHandler()
    private val viewModel = PermissionsViewModel(handler)

    fun testFirstDenial_shouldShowRationale() {
        handler.shouldShowRationale = true
        handler.cameraResult =
            PermissionResult.DENIED(true)

        viewModel.onCameraRequested()

        assertEquals(
            PermissionUiState.Denied(true),
            viewModel.uiState.value
        )
    }

    fun testNeverAskAgain_redirectToSettings() {
        handler.shouldShowRationale = false
        handler.cameraResult =
            PermissionResult.DENIED(false)

        viewModel.onCameraRequested()

        assertEquals(
            PermissionUiState.RedirectToSettings,
            viewModel.uiState.value
        )
    }
}

계측 테스트의 주요 시나리오는 첫 번째 거부 후 설명 대화상자가 실제로 표시되는지 확인하는 것입니다. Idling Resources와 함께 Espresso를 사용하여 시스템 대화상자를 기다린 다음 Deny를 누르고, 사용자 지정 설명 대화상자의 표시를 확인하고 Allow를 눌러 부여를 확인합니다. UIAutomator는 버튼 텍스트로 시스템 대화상자와 상호 작용할 수 있어 테스트를 더 안정적으로 만듭니다.

또한 설명 대화상자 내에서 거부 시나리오를 테스트해야 합니다. 사용자가 사용자 지정 설명에서 Deny를 누르면 Never Ask Again이 아직 활성화되지 않았으므로 shouldShowRequestPermissionRationale가 다시 true를 반환해야 합니다. 모범 사례는 연속 두 번 거부 후 즉시 설정으로 리디렉션하여 반복적인 설명으로 사용자를 귀찮게 하지 않고 앱 평점을 낮추지 않는 것입니다.

자주 묻는 질문

shouldShowRequestPermissionRationale는 무엇을 반환하나요?

true — 요청이 이전에 거부되었고 Never Ask Again이 설정되지 않은 경우입니다. false — 권한이 요청된 적이 없거나, 부여되었거나, 영구적으로 차단된 경우입니다. false + DENIED 조합은 추가 플래그를 통한 확인이 필요합니다.

설명 대화상자는 언제 표시해야 하나요?

shouldShowRequestPermissionRationale가 true를 반환한 경우, 사용자의 첫 번째 거부 후에만 설명을 표시하십시오. 첫 번째 요청 전에는 설명이 필요하지 않습니다. 이는 UX를 저하시키고 불필요한 대화상자를 만듭니다.

첫 번째 요청과 Never Ask Again을 구별하는 방법은?

SharedPreferences 또는 SavedStateHandle에 isFirstRequest 플래그를 저장합니다. shouldShowRationale = false, checkSelfPermission = DENIED이고 플래그가 true인 경우 Never Ask Again이 활성화된 것입니다. 플래그가 false인 경우 첫 번째 요청입니다.

Never Ask Again인 경우 어떻게 해야 하나요?

사용자를 ACTION_APPLICATION_DETAILS_SETTINGS로 리디렉션하는 “설정 열기” 버튼이 있는 대화상자를 표시합니다. requestPermissions를 다시 호출하지 마십시오. 대화상자가 나타나지 않으며 결과가 메시지 없이 DENIED로 반환됩니다.

shouldShowRequestPermissionRationale를 테스트하는 방법은?

단위 테스트에서는 구성 가능한 shouldShowRationale 필드가 있는 FakePermissionHandler를 사용합니다. 계측 테스트에서는 시스템 대화상자 에뮬레이션과 함께 Espresso 또는 UIAutomator를 사용합니다. 표의 4가지 상태를 모두 확인합니다.

요약

  • shouldShowRequestPermissionRationale — 권한 요청 전에 설명을 표시해야 하는지 결정하는 메서드입니다.
  • Never Ask Again 없이 첫 번째 거부 후 true를 반환하고 다른 세 가지 경우에는 false를 반환합니다.
  • false + DENIED 조합은 가장 어려운 시나리오로, 구별을 위해 추가 플래그가 필요합니다.
  • 설명 대화상자는 거부 후에만 표시되며, 첫 번째 요청 전에는 표시되지 않습니다.
  • 더 나은 UX를 위해 모달 대화상자 대신 바텀 시트나 인라인 요소를 사용하십시오.
  • Never Ask Again이 활성화된 경우 — ACTION_APPLICATION_DETAILS_SETTINGS를 통해 설정으로 리디렉션합니다.
  • 기능 사용 시점에 연결된 컨텍스트 기반 설명은 허용률을 80퍼센트까지 높입니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기