Runtime Permission은 애플리케이션 실행 중에 권한을 요청하는 메커니즘으로, Android 6.0(API 23)에서 도입되었습니다. 설치 시 권한을 부여하는 것과 달리, 런타임 권한을 사용하면 사용자가 언제든지 민감한 데이터(카메라, 위치 정보, 연락처)에 대한 액세스를 허용하거나 취소할 수 있습니다. Android Developers(2026)에 따르면, Google Play 앱의 85% 이상이 하나 이상의 런타임 권한을 사용합니다.
핵심 포인트
Runtime Permission은 해당 기능이 사용자에게 실제로 필요한 시점에 앱이 민감한 데이터에 대한 액세스를 요청하는 Android 보안 모델입니다. Android 6.0 이전에는 모든 권한이 앱 설치 시 부여되었으며, 사용자는 앱을 완전히 제거하지 않고는 권한을 취소할 수 없었습니다.
Android 6.0 이전에는 사용자가 설치 시 모든 권한 목록을 보고 모두 수락하거나 설치를 거부할 수 있었습니다. 2015년 연구에 따르면 사용자의 87%가 설치 시 권한 목록을 읽지 않는 것으로 나타났습니다. Android 6.0은 런타임 권한을 도입하여 권한을 일반(자동)과 위험(요청 필요)으로 구분했습니다. Android 11은 일회성 권한을 추가했습니다 — 앱을 닫으면 자동 취소됩니다. Android 13은 포토 피커와 푸시 알림을 별도의 런타임 권한으로 도입했습니다.
iOS는 iOS 10부터 유사한 모델을 사용하며, 카메라, 마이크, 위치 정보에 대한 액세스는 첫 사용 시 요청됩니다. 그러나 iOS에는 “일반 권한” 개념이 없습니다 — 각 권한이 명시적으로 요청되며, 개발자가 시스템 설정을 통해 다시 요청할 때까지 거부 상태가 유지됩니다.
Runtime Permission은 requestPermissions() 메서드(AndroidX — ActivityResultLauncher)에 의해 호출되는 시스템 대화상자를 통해 작동합니다. 시스템은 설명과 함께 표준 대화상자를 표시하고, 사용자는 “허용” 또는 “거부”를 선택합니다. 응답 후 앱이 사용자의 결정을 처리하는 콜백이 트리거됩니다.
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
startCamera()
} else {
showPermissionDeniedDialog()
}
}
}
private fun checkCameraPermission() {
when {
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED -> {
startCamera()
}
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) -> {
showRationaleDialog { requestPermissionLauncher.launch(Manifest.permission.CAMERA) }
}
else -> {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
shouldShowRequestPermissionRationale 메서드는 사용자가 이미 한 번 요청을 거부한 경우 true를 반환합니다. 이 경우 앱에 권한이 필요한 이유를 설명하는 대화상자를 표시한 후에 다시 요청하는 것이 좋습니다. 이렇게 하면 사용자 동의 가능성이 30~40% 증가합니다(Google I/O 2024 데이터).
Android는 모든 권한을 여러 보호 수준으로 분류합니다: 일반, 위험, 서명 및 특수. 일반 권한은 설치 시 자동으로 부여됩니다. 위험 권한은 런타임 요청이 필요합니다. 서명 권한은 동일한 인증서로 서명된 앱만 사용할 수 있습니다.
| 그룹 | 권한 | API 수준 |
|---|---|---|
| CAMERA | CAMERA | API 23+ |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATION | API 23+(백그라운드는 API 29+) |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, READ_MEDIA_IMAGES(API 33+) | API 23+(API 33에서 변경) |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | API 23+ |
| MICROPHONE | RECORD_AUDIO | API 23+ |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | API 23+ |
| NOTIFICATIONS | POST_NOTIFICATIONS | API 33+ |
특수 권한(SYSTEM_ALERT_WINDOW, WRITE_SETTINGS, MANAGE_EXTERNAL_STORAGE)은 Settings.ACTION_MANAGE_OVERLAY_PERMISSION을 통해 시스템 설정으로 추가 이동이 필요합니다. 이러한 권한은 표준 시스템 대화상자를 통해 요청할 수 없으며 설정 화면에서 사용자의 명시적 조치가 필요합니다.
Android 12는 런타임 권한 모델에 중요한 변경 사항을 도입했습니다. 일회성 권한은 카메라, 마이크 또는 위치 정보에 대한 액세스를 한 세션에만 허용합니다. 사용자가 앱을 닫으면 권한이 자동으로 취소됩니다. 개인정보 보호 표시기는 앱이 카메라나 마이크를 사용할 때 상태 표시줄에 표시되는 녹색 표시기입니다.
// Android 12+ — 일회성 위치 권한 처리
private fun checkLocationPermission() {
val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val fineLocationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION]
val coarseLocationGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION]
if (fineLocationGranted == true) {
showUserLocation()
} else {
showLocationDisabledDialog()
}
}
permissionLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}
// 시스템에 의해 권한이 취소되었는지 확인(Android 12+)
class PermissionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_PERMISSION_REVOCATION) {
handleRevokedPermission(intent.getStringExtra(Intent.EXTRA_REVOKED_PERMISSION))
}
}
}
Android 13은 POST_NOTIFICATIONS 권한을 위험 그룹에 추가하여 푸시 알림 전송을 위한 명시적 요청이 필요하게 했습니다. Android 14는 백그라운드 위치 정보에 제한을 도입했습니다: 앱이 백그라운드 위치를 요청할 때마다 사용자의 명시적 승인을 받아야 합니다. 포토 피커(API 33+)는 이미지 선택을 위해 READ_EXTERNAL_STORAGE의 필요성을 대체했습니다.
권한 요청에 대한 사용자의 거부는 정상적인 상황이며 올바르게 처리해야 합니다. 거부에는 두 가지 유형이 있습니다: 일회성(사용자가 “거부”를 탭)과 영구적(사용자가 “다시 묻지 않음” 선택). 두 번째 경우 시스템 대화상자가 더 이상 표시되지 않으며 앱이 사용자를 시스템 설정으로 리디렉션해야 합니다.
첫 번째 거부 후 앱은 이유 설명 대화상자를 표시해야 합니다 — 권한이 필요한 이유에 대한 자체 설명입니다. 사용자가 다시 거부하면 앱은 Settings.ACTION_APPLICATION_DETAILS_SETTINGS를 통해 앱 설정 화면으로 리디렉션해야 합니다. Material 3는 더 자연스러운 UX를 위해 PermissionRequestBottomSheet 사용을 권장합니다.
거부 시 앱 기능을 완전히 차단하지 않는 것이 중요합니다. 예를 들어 사용자가 위치 정보를 거부한 경우 앱이 수동 주소 입력을 제공해야 합니다. 카메라의 경우 갤러리에서 이미지를 업로드할 수 있도록 합니다. Google은 모든 런타임 권한에 대해 항상 대체 메커니즘을 제공할 것을 권장합니다.
런타임 권한은 단순한 기술적 메커니즘이 아니라 앱에 대한 사용자 신뢰의 요소이기도 합니다. 부적절한 시점(예: 첫 실행 시)에 권한을 요청하면 동의 가능성이 크게 줄어듭니다. Google Play 스토어는 권한 요청의 빈도와 컨텍스트를 분석합니다: 과도한 요청이 있는 앱은 검색 순위가 낮아집니다.
컨텍스트 — 권한이 필요한 작업을 수행하기 직전에 권한을 요청합니다. 최소 — 기능 작동에 실제로 필요한 권한만 요청합니다. 투명성 — 시스템 대화상자 전에 권한이 필요한 이유를 사용자에게 설명합니다. 취소 — 런타임에서 권한 취소를 올바르게 처리하려면 ACTION_PERMISSION_REVOCATION을 구독합니다.
런타임 권한 테스트를 위해 adb 명령을 사용하세요: adb shell pm revoke <package> android.permission.CAMERA는 앱을 재설치하지 않고도 권한 취소를 시뮬레이션할 수 있습니다. Espresso와 UiAutomator는 GrantPermissionRule을 통해 권한 대화상자 테스트를 지원합니다. 런타임 권한이 있는 앱의 경우 CI/CD 파이프라인에 이러한 도구를 통합하는 것이 필수입니다.
Google Play Console은 권한 감사 섹션을 제공하여 개발자가 권한이 요청되는 빈도, 액세스를 허용하는 사용자 비율, 취소된 권한을 확인할 수 있습니다. 이 데이터를 분석하면 비효율적인 요청을 식별하고 UX를 최적화하는 데 도움이 됩니다. 예를 들어 40% 미만의 사용자가 위치 정보를 허용하는 경우 요청 시기를 재검토하고 더 설득력 있는 이유를 추가하는 것을 고려하세요.
권한 관련 ANR(애플리케이션 응답 없음) 모니터링을 위한 Android Vitals 사용도 중요합니다. 권한 요청이 메인 스레드에서 실행되거나 시스템 대화상자가 UI를 차단하면 느린 기기에서 ANR이 발생할 수 있습니다. 사용자 인터페이스 차단을 방지하려면 권한 확인 및 요청을 별도 스레드로 이동하거나 Kotlin 코루틴을 사용하여 비동기적으로 처리하세요.
자주 묻는 질문
shouldShowRequestPermissionRationale은 영구적 거부(사용자가 “다시 묻지 않음” 선택) 시 false를 반환합니다. 이 메서드는 일회성 거부 시 true를 반환하여 이유 설명 대화상자를 표시할 수 있게 합니다. 메서드가 false를 반환하는 경우 유일한 옵션은 사용자를 시스템 설정으로 리디렉션하는 것입니다.
네, ActivityResultContracts.RequestMultiplePermissions를 사용하면 한 번의 호출로 권한 배열을 요청할 수 있습니다. 시스템은 각 권한에 대해 순차적으로 대화상자를 표시합니다. 논리적으로 관련된 권한(예: 비디오 녹화를 위한 CAMERA와 RECORD_AUDIO)을 그룹화하는 것이 좋지만, 한 번에 2~3개 이상 요청하지 마세요.
Android TV는 TV 화면에 대화상자를 표시하는 동일한 런타임 권한 모델을 사용합니다. Wear OS 버전 3+는 런타임 권한을 지원하지만 대화상자는 시계에 표시됩니다. Android Auto의 경우 모든 권한은 휴대폰에서 요청되며, 자동차 시스템은 브리지 연결을 통해 이미 승인된 권한을 받습니다.
예비 정보에 따르면 Android 16은 24시간 후 자동 취소와 함께 일회성 권한에 대한 “권한 만료”를 도입합니다. 백그라운드 위치에 대한 더 엄격한 요구 사항과 새로운 카테고리(환경 센서, Wi-Fi 스캐닝)에 대한 위험 권한 목록 확장도 예상됩니다. 정확한 세부 사항은 2027년 3분기에 공개될 예정입니다.
iOS는 “일반 권한”을 지원하지 않습니다 — 각 권한이 시스템 대화상자를 통해 명시적으로 요청됩니다. 사용자는 설정을 통해 언제든지 권한을 취소할 수 있습니다. 주요 차이점은 iOS가 checkSelfPermission에 상응하는 방식으로 권한 상태를 사전 확인하지 않는다는 것입니다: 시스템은 보호된 API에 처음 액세스할 때 자동으로 대화상자를 표시합니다.
요약
POST_NOTIFICATIONS를 런타임 권한으로 추가했습니다. Android 14는 백그라운드 위치 정보 요구 사항을 강화했습니다.READ_EXTERNAL_STORAGE의 필요성을 대체합니다.턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.