AndroidManifest Permissions: 핵심 개념, 선언 및 권한 유형

저자: IT Sectr 게시일: 2026-05-21 읽는 시간: 10 분

AndroidManifest Permissions는 AndroidManifest.xml 파일의 권한 선언으로, 애플리케이션이 액세스할 수 있는 시스템 리소스와 데이터를 결정합니다. Android는 해당 API를 사용하기 전에 매니페스트에서 각 권한을 선언하도록 요구합니다. 카메라 및 위치 정보부터 SMS 전송 및 연락처 액세스까지 모두 포함됩니다. Android Developer Documentation에 따르면, 각 권한은 네 가지 보호 수준(normal, dangerous, signature, special) 중 하나에 속합니다.

핵심 사항

  • AndroidManifest.xml — 모든 애플리케이션 권한 선언이 포함된 매니페스트 파일
  • 보호 수준 — normal, dangerous, signature, special, 각각 다른 요청 메커니즘
  • Runtime Permission — dangerous 권한은 런타임에 요청 필요 (Android 6+)
  • 선언 vs 요청 — 매니페스트 선언은 필수, dangerous는 코드에서 추가 요청 필요
  • 그룹 — 권한은 그룹화되며, 하나에 동의하면 전체 그룹에 대한 액세스 권한 부여

AndroidManifest Permissions란?

AndroidManifest Permissions는 보호된 데이터 및 시스템 기능에 대한 애플리케이션 액세스를 제어하는 Android의 보안 메커니즘입니다. 모든 애플리케이션은 요소를 사용하여 AndroidManifest.xml 파일에서 필요한 권한을 선언해야 합니다. 선언 없이 해당 API를 호출하면 SecurityException 보안 오류가 발생합니다.

Android 권한 모델은 여러 진화 단계를 거쳤습니다. Android 6.0(API 23) 이전에는 모든 권한이 설치 시 부여되었습니다. 사용자는 전체 목록을 보고 애플리케이션 설치에 동의하거나 거부했습니다. Android 6.0부터 dangerous 수준의 권한은 런타임에(Runtime Permissions) 요청되어 사용자에게 더 유연한 제어를 제공합니다.

권한은 네 가지 보호 수준으로 나뉩니다: normal(설치 시 자동 부여), dangerous(런타임 요청 필요), signature(동일한 인증서로 서명된 애플리케이션만 사용 가능), special(설정에서 별도 활성화 필요). 각 수준에는 고유한 부여 및 취소 메커니즘이 있습니다.

Google I/O 2024에 따르면, Android 15는 더 세분화된 권한을 도입할 계획입니다. 사용자는 미디어 라이브러리 전체가 아닌 특정 파일에만 액세스 권한을 부여할 수 있습니다. 이는 기본적으로 제공되는 데이터 양을 최소화하려는 Android의 추세를 계속합니다.

iOS 권한 모델과의 차이점

모든 권한이 런타임에 요청되는 iOS와 달리, Android는 권한을 설치 시간(install-time)과 런타임(runtime)으로 나눕니다. normal 수준은 사용자 알림 없이 설치 시 자동으로 부여됩니다. dangerous 수준은 iOS와 같이 명시적인 대화상자가 필요합니다.

또 다른 차이점: Android에서 권한은 권한 그룹으로 그룹화됩니다. 사용자가 카메라 액세스에 동의하면 애플리케이션이 자동으로 마이크 액세스 권한을 얻습니다. 둘은 동일한 MICROPHONE 그룹에 속하기 때문입니다. iOS에서는 각 권한이 그룹과 관계없이 독립적으로 요청됩니다.

Android 버전별 권한 진화

Android 버전권한 모델 변경 사항
Android 1.0~5.x모든 권한이 설치 시 부여됨
Android 6.0(API 23)dangerous 수준을 위한 Runtime Permissions 도입
Android 10(API 29)Scoped Storage — 파일 시스템 액세스 제한
Android 11(API 30)자동 재설정 권한 — 사용하지 않는 권한 재설정
Android 14(API 34)미디어 액세스(사진, 비디오, 오디오)를 위한 런타임 권한

권한 유형

Android는 권한에 대해 네 가지 보호 수준을 정의하며, 각각 고유한 부여 규칙이 있습니다. 각 수준을 자세히 살펴보겠습니다.

Normal 권한 (설치 시)

Normal 권한은 사용자 알림이나 요청 없이 애플리케이션 설치 시 자동으로 부여됩니다. 사용자 개인정보를 위협하지 않는 저위험 기능을 포함합니다: INTERNET, ACCESS_NETWORK_STATE, VIBRATE, BLUETOOTH. 사용자는 동의 대화상자를 보지 않습니다. 권한은 설치 시 부여된 것으로 간주됩니다.

개발자는 normal 권한에 대해 코드에서 요청을 처리할 필요가 없습니다. 매니페스트에 선언하는 것으로 충분합니다. 그러나 Android 12+에서는 Google Play에서 설치할 때 사용자가 모든 normal 권한을 나열하는 “권한” 탭을 볼 수 있어 투명성이 향상됩니다. Statista(2024)에 따르면, Google Play 앱의 90% 이상이 가장 일반적인 normal 권한으로 INTERNET을 사용합니다.

Dangerous 권한 (런타임)

Dangerous 권한은 개인정보를 침해할 수 있는 데이터 및 기능에 대한 액세스를 포함합니다: 카메라, 마이크, 위치 정보, 연락처, SMS, 전화, 캘린더, 신체 센서. 이러한 권한에는 2단계 메커니즘이 필요합니다: 매니페스트 선언 + ActivityCompat.requestPermissions()를 통한 런타임 요청.

사용자는 dangerous 권한을 거부할 수 있으며, 애플리케이션은 이 시나리오를 적절히 처리해야 합니다. Android 11+에서 사용자가 두 번 거부하면 이후 요청은 시스템 대화상자를 표시하지 않습니다. 시스템이 자동으로 DENIED를 반환합니다. 이 경우 애플리케이션은 사용자를 설정으로 안내해야 합니다.

Signature 및 Special 권한

signature 수준 — 애플리케이션이 시스템 또는 권한을 정의한 다른 애플리케이션과 동일한 인증서로 서명된 경우 권한이 자동으로 부여됩니다. 시스템 및 엔터프라이즈 애플리케이션에 사용됩니다. 예: BIND_ACCESSIBILITY_SERVICE — 시스템 애플리케이션만 사용 가능.

special 수준(SYSTEM_ALERT_WINDOW, WRITE_SETTINGS, REQUEST_INSTALL_PACKAGES, MANAGE_EXTERNAL_STORAGE) — 시스템 설정을 통한 사용자의 명시적 작업이 필요합니다. 애플리케이션은 Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)을 사용하여 설정 페이지를 열 수 있습니다. Google Play는 special 권한 사용을 제한하며 게시 시 양식에 정당성 설명이 필요합니다.

Runtime Permission: dangerous 권한 다루기

Android 6.0부터 모든 dangerous 권한은 런타임 요청이 필요합니다. Kotlin에서 runtime permissions의 전체 작업 주기를 살펴보겠습니다.

권한 확인 및 요청

dangerous 권한이 필요한 API를 호출하기 전에 항상 ContextCompat.checkSelfPermission()을 통해 현재 상태를 확인하세요. 상태가 PERMISSION_GRANTED이면 API를 호출할 수 있습니다. PERMISSION_DENIED이면 ActivityResultContract RequestPermission(AndroidX) 또는 더 이상 사용되지 않는 requestPermissions()를 통해 권한을 요청해야 합니다.

여러 권한을 동시에 요청하려면 ActivityResultContracts.RequestMultiplePermissions을 사용하는 것이 좋습니다. Google은 관련 권한(예: 비디오 녹화를 위한 카메라 + 마이크)을 하나의 대화상자로 그룹화하여 사용자가 요청의 전체 맥락을 볼 수 있도록 권장합니다.

kotlin
import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat

class CameraActivity : AppCompatActivity() {
    private val requestPermissionLauncher =
        registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted: Boolean ->
            if (isGranted) {
                openCamera()
            } else {
                explainWhyPermissionNeeded()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        checkCameraPermission()
    }

    private fun checkCameraPermission() {
        when {
            ContextCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED -> {
                openCamera()
            }
            shouldShowRequestPermissionRationale(
                Manifest.permission.CAMERA
            ) -> {
                showRationale()
            }
            else -> {
                requestPermissionLauncher.launch(
                    Manifest.permission.CAMERA
                )
            }
        }
    }
}

“다시 묻지 않음” 거부 처리

사용자가 두 번 거부하면 Android는 요청을 “Never ask again” 상태로 전환합니다. 이 경우 shouldShowRequestPermissionRationale()이 false를 반환하고 시스템 대화상자가 표시되지 않습니다. 애플리케이션은 Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)를 통해 사용자를 시스템 설정으로 안내해야 합니다.

중요: 첫 번째 거부 직후 설정을 열도록 제안하는 대화상자를 표시하지 마세요. 이는 공격적인 행동으로 인식됩니다. shouldShowRequestPermissionRationale()을 사용하여 설명이 필요한지 확인하세요. Material Design Guidelines는 단순한 “설정 열기” 버튼이 아닌 액세스의 가치를 설명하는 화면을 표시할 것을 권장합니다.

kotlin
private fun openAppSettings() {
    Intent(
        Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
        Uri.fromParts("package", packageName, null)
    ).also { intent ->
        startActivity(intent)
    }
}

private fun showPermissionSettings() {
    AlertDialog.Builder(this)
        .setTitle("카메라 액세스")
        .setMessage("설정에서 카메라 액세스 허용, "
            + "프로필 사진 촬영")
        .setPositiveButton("설정 열기") { _, _ ->
            openAppSettings()
        }
        .setNegativeButton("취소", null)
        .show()
}

AndroidManifest.xml에서 권한 선언

AndroidManifest.xml 파일에는 애플리케이션이 사용하는 각 권한에 대한 요소가 포함됩니다. 권한은 수준에서 요소 앞에 선언됩니다.

선언 구문

각 권한은 android:name 속성을 사용하여 전체 권한 이름을 지정하는 별도의 요소로 선언됩니다. 특정 Android 버전에서 도입된 권한의 경우 maxSdkVersion 속성을 사용하여 선언을 필요한 버전으로만 제한하세요. 이렇게 하면 호환성이 향상됩니다.

예를 들어, WRITE_EXTERNAL_STORAGE 권한은 Android 10+(Scoped Storage)에서 필요하지 않으므로 maxSdkVersion="28"(Android 9)을 지정하세요. 이렇게 하면 최신 버전에서 사용자의 불필요한 질문을 방지할 수 있습니다. Android Studio는 Lint를 통해 권장 maxSdkVersion에 대해 경고합니다.

xml
<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Normal permissions (install-time) -->
    <uses-permission
        android:name="android.permission.INTERNET" />
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- Dangerous permissions (runtime) -->
    <uses-permission
        android:name="android.permission.CAMERA" />
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!-- Legacy storage permission limited to API 28 and below -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="28" />

    <uses-feature
        android:name="android.hardware.camera"
        android:required="false" />

    <application>
        <!-- ... -->
    </application>
</manifest>

필터링을 위한 사용

요소는 애플리케이션이 특정 하드웨어(카메라, GPS, NFC)를 필요로 함을 나타냅니다. android:required="false" 속성을 사용하면 해당 하드웨어가 없는 기기에도 애플리케이션을 설치할 수 있습니다. 가용성은 코드에서 확인됩니다. required="true"인 경우 Google Play가 애플리케이션을 필터링하여 부적합한 기기에서 사용할 수 없게 만듭니다.

모든 하드웨어 기능에 대해 required="false"로 설정하고 PackageManager.hasSystemFeature()를 통해 프로그래밍 방식으로 가용성을 확인하는 것이 좋습니다. 이렇게 하면 애플리케이션의 대상 사용자가 확장됩니다. 유일한 예외는 기능이 애플리케이션 작동에 중요한 경우입니다(GPS 없는 택시 호출 앱은 의미가 없습니다).

모범 사례 및 오류

적절한 권한 관리는 Android 애플리케이션 품질의 핵심 요소입니다. 주요 권장 사항과 일반적인 오류를 살펴보겠습니다.

요청하는 권한 최소화

애플리케이션 작동에 실제로 필요한 권한만 요청하세요. 추가 권한마다 설치 전환율이 낮아지고 거부 횟수가 증가합니다. Google Play Console은 권한 세트로 인해 설치를 거부한 사용자 수를 표시합니다. AppBrain(2024)에 따르면, 10개 이상의 dangerous 권한이 있는 애플리케이션은 설치 수가 35% 적습니다.

정기적으로 권한 목록을 검토하세요. 특히 일부 권한이 선택 사항이 되는 최신 Android 버전으로 마이그레이션할 때 사용하지 않는 권한을 제거하세요. 예를 들어, Android 13+의 사진 선택기(ActivityResultContracts.PickVisualMedia)를 사용하면 dangerous READ_MEDIA_IMAGES 권한 없이 미디어 라이브러리에 액세스할 수 있습니다.

요청 전 설명 표시

dangerous 권한을 요청하기 전에 사용자에게 해당 권한이 필요한 이유와 제공하는 가치를 설명하는 화면을 표시하세요. Material Design은 아이콘, 간결한 텍스트 및 “계속” 버튼이 있는 바텀 시트 또는 대화상자를 권장합니다. 설명을 표시하면 직접 요청에 비해 동의율이 20~30% 증가합니다.

launch()를 호출하기 전에 shouldShowRequestPermissionRationale()을 확인하세요. true이면 설명을 표시합니다. false이면 권한이 이미 부여되었거나 사용자가 영구적으로 거부한 것입니다(다시 묻지 않음). 후자의 경우 요청을 반복하는 대신 “설정 열기” 버튼을 표시하세요.

모든 권한 시나리오 테스트

가능한 모든 시나리오를 테스트하세요: 권한 부여, 거부, 영구 거부, 설정에서 권한 취소, 권한 재설정(Android 11+ 자동 재설정). 각 시나리오는 충돌이나 데이터 손실 없이 처리되어야 합니다. Android Testing Guide는 테스트 자동화를 위해 TestPermission 라이브러리 사용을 권장합니다.

애플리케이션 실행 중 사용자가 권한을 취소하는 시나리오(앱 최소화 → 설정 → 취소)에 특히 주의하세요. 애플리케이션으로 돌아오면 onResume()에서 모든 권한을 다시 확인하세요. 권한 상태 캐싱에 의존하지 마세요. 사용자는 언제든지 변경할 수 있습니다.

일반적인 오류

  • checkSelfPermission을 먼저 확인하지 않고 권한 요청 — 불필요한 대화상자 유발
  • shouldShowRequestPermissionRationale 무시 — 첫 거부 후 UX 저하
  • 컨텍스트 없이 권한 요청(“액세스를 허용하시겠습니까?”만) — 동의율 감소
  • Android 10+에서 maxSdkVersion 없이 WRITE_EXTERNAL_STORAGE 사용 — 불필요한 요청
  • onResume에서 권한 확인 누락 — 설정에서 권한 취소 놓침

자주 묻는 질문

SDK가 요청하는 경우에도 권한을 선언해야 하나요?

네, SDK가 매니페스트에 권한을 포함하면 빌드 시 애플리케이션 매니페스트와 병합됩니다. AndroidManifest.xml에서 tools:node="remove"를 사용하여 불필요한 SDK 권한을 제거할 수 있습니다.

권한 거부를 처리하지 않으면 어떻게 되나요?

권한 없이 API를 호출하면 SecurityException이 발생하여 애플리케이션이 충돌합니다. 해당 API를 사용하기 전에 항상 권한 상태를 확인하고 거부를 적절히 처리하세요.

개발 중에 권한을 재설정하려면 어떻게 하나요?

기기 설정에서: 설정 → 앱 → [앱 이름] → 권한. 모든 권한을 재설정하려면 adb 명령을 사용하세요: adb shell pm reset-permissions.

Activity 없이 권한을 요청할 수 있나요?

네, Fragment 또는 Service에서 ActivityResultLauncher를 사용하여 가능합니다. 그러나 요청 대화상자는 항상 Activity UI 컨텍스트가 필요합니다. Service의 경우 요청 Activity를 여는 Intent가 포함된 Notification을 표시할 수 있습니다.

권한에 maxSdkVersion이 필요한 이유는?

예를 들어, WRITE_EXTERNAL_STORAGE는 Android 10+(Scoped Storage)에서 필요하지 않습니다. android:maxSdkVersion="28"을 지정하면 최신 버전에서 권한 선언을 제외하여 호환성을 개선하고 요청되는 권한 목록을 줄일 수 있습니다.

요약

  • AndroidManifest Permissions — Android에서 시스템 리소스에 액세스하기 위한 필수 선언
  • 4가지 보호 수준 — normal, dangerous, signature, special, 각각 다른 부여 메커니즘
  • Runtime Permissions — dangerous 권한은 런타임 요청 필요 (Android 6+)
  • 권한 그룹 — 그룹 내 하나의 권한에 동의하면 그룹의 모든 권한에 액세스 가능
  • 설명 — 요청 전 설명을 표시하면 동의율 20~30% 증가
  • 최소화 — 필요한 권한만 요청하고 maxSdkVersion 사용
  • API 호출 전 항상 권한 상태를 확인하고 모든 거부 시나리오 처리

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

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

프로젝트 논의

더 읽어보기