안드로이드 시스템·Compose 용어 사전
보안dangerous · shouldShowRequestPermissionRationale

런타임 권한

위험 권한을 실행 중 사용자에게 요청하는 절차. 거부 상태를 항상 처리해야 한다.

위험(dangerous) 권한을 실행 중에 사용자에게 요청하는 절차.

  • normal — 설치 시 자동 승인 (INTERNET · VIBRATE · ACCESS_NETWORK_STATE)
  • dangerous — 실행 중 사용자 동의 필요 (CAMERA · 위치 · 연락처 · 알림)
  • signature — 같은 키로 서명된 앱만
private val launcher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { granted -> if (granted) openCamera() else showRationale() }

when {
    ContextCompat.checkSelfPermission(this, CAMERA) == PERMISSION_GRANTED -> openCamera()
    shouldShowRequestPermissionRationale(CAMERA) -> showWhyDialog()   // 한 번 거부했다
    else -> launcher.launch(CAMERA)
}

세 갈래를 다 처리해야 한다

  • 허용됨 — 바로 진행

  • 거부했지만 재요청 가능 — 왜 필요한지 설명하고 다시 묻는다

  • 영구 거부 — 시스템 다이얼로그가 안 뜬다 → 설정으로 안내한다

  • 세 번째를 빠뜨리면 "버튼을 눌러도 아무 일도 안 일어나는" 앱이 된다

// 영구 거부 판별 — 요청했는데 다이얼로그가 안 뜨고 바로 false 가 온 경우
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
       Uri.fromParts("package", packageName, null)).let(::startActivity)

언제든 취소될 수 있다

  • 사용자가 설정에서 권한을 끄면

    • Android 11+ 는 앱 프로세스를 종료한다
    • "오래 안 쓴 앱" 은 권한이 자동 해제된다 (자동 초기화)
  • 권한은 '한 번 받으면 끝' 이 아니다. 쓰기 직전에 늘 확인한다

버전별로 늘어난 것들

  • Android 11 — 위치 '이번만 허용' · 백그라운드 위치는 별도 화면에서 재요청
  • Android 12 — 대략적/정확한 위치 선택 · 근처 기기 권한 분리
  • Android 13 — POST_NOTIFICATIONS 가 런타임 권한이 됐다
    • READ_EXTERNAL_STORAGE 가 미디어 타입별로 쪼개졌다
  • Android 14 — 부분 미디어 접근 (사진 몇 장만 선택)

권한을 아예 피하는 길

  • 사진 선택 — Photo Picker (ACTION_PICK_IMAGES) → 저장소 권한 불필요
  • 파일 선택 — Storage Access Framework → 권한 불필요
  • 연락처 선택 ContactsContract 의 피커 인텐트 → 권한 불필요

"권한을 요청하지 않고 같은 목적을 이루는 API 가 있는가" 를 먼저 본다

면접 함정

  • "매니페스트에 선언하면 쓸 수 있다" → dangerous 권한은 런타임 요청이 필수다.
  • "한 번 허용하면 영구다" → 자동 초기화와 사용자 회수가 있다.

Compose에서의 권한 처리

val permissionState = rememberPermissionState(Manifest.permission.CAMERA)

when {
    permissionState.status.isGranted -> CameraPreview()
    permissionState.status.shouldShowRationale -> RationaleCard(
        onRequest = { permissionState.launchPermissionRequest() }
    )
    else -> LaunchedEffect(Unit) { permissionState.launchPermissionRequest() }
}
// implementation("com.google.accompanist:accompanist-permissions:...")

요청 시점 설계

❌ 앱 첫 실행에 권한 5개를 연속으로 묻는다

  • 맥락이 없어 대부분 거부하고, 영구 거부로 굳는다

✅ 그 기능을 쓰려는 순간에 묻는다 "사진을 첨부하려면 카메라 권한이 필요합니다" 를 먼저 보여 주고 사용자가 '계속' 을 누르면 시스템 다이얼로그를 띄운다

한 번 영구 거부되면 되돌리려면 사용자가 설정에 들어가야 한다 — 첫 요청이 사실상 유일한 기회다

권한 없이도 동작하는 경로

권한이 없다고 기능을 막지 않는다
  카메라 거부 → 갤러리에서 선택하는 경로를 남긴다
  위치 거부   → 주소를 직접 입력하게 한다
  알림 거부   → 앱 안에서 배지로 알린다

"권한을 안 주면 못 쓴다" 는 앱은 삭제된다

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 권한·보안 — 런타임 권한·저장소·암호화·네트워크