AndroidManifest.xml은 모든 Android 애플리케이션의 필수 구성 파일로, 앱의 구성 요소, 권한 및 메타데이터를 설명합니다. Android 시스템은 각 애플리케이션을 설치하고 실행할 때 이 파일을 읽습니다. Android Developers, 2025에 따르면, 올바른 매니페스트 없이는 애플리케이션이 기기에 설치되지 않습니다. AndroidManifest.xml은 운영 체제를 위해 Activity, Service, BroadcastReceiver 및 ContentProvider를 등록합니다.
핵심 요약
AndroidManifest.xml은 XML 형식의 루트 구성 파일로, 모든 Android 프로젝트는 app/src/main 디렉토리에 이 파일을 포함해야 합니다. Android 시스템은 애플리케이션 코드를 실행하기 전에 APK 파싱 단계에서 이 파일을 분석합니다. 매니페스트에 구문 오류가 있거나 필수 선언이 누락된 경우 설치가 오류 메시지와 함께 중단됩니다.
이 파일에는 애플리케이션의 전체 선언이 포함됩니다: 모든 구성 요소 목록(Activity, Service, BroadcastReceiver, ContentProvider), 요청된 권한, 최소 SDK 버전, 하드웨어 요구 사항, 테마 및 스타일 구성. 시스템이나 다른 애플리케이션이 호출할 수 있는 모든 구성 요소는 매니페스트에 명시적으로 선언되어야 합니다. 이는 보안 요구 사항입니다: 명시적 선언 없이는 구성 요소를 호출할 수 없습니다.
올바르게 구성된 매니페스트 없이는 애플리케이션을 Google Play 또는 사이드로딩을 통해 설치할 수 없습니다. 시스템은 APK 파싱 단계에서 매니페스트를 확인하고 오류가 있으면 설치를 거부합니다. Google Play도 매니페스트를 스캔하여 안전하지 않은 구성을 감지합니다: exported=true이면서 intent-filter가 없는 구성 요소에 경고를 표시하고, targetSdk 34+에 필수 권한이 없으면 게시를 차단합니다. 따라서 매니페스트 구조를 이해하는 것은 Android 개발자의 필수 기술입니다.
Android 애플리케이션의 모든 구성 요소는 매니페스트에 명시적으로 등록되어야 합니다. 이는 네 가지 구성 요소 유형 모두에 대한 플랫폼의 필수 요구 사항입니다. 등록 없이는 시스템이 구성 요소를 생성할 수 없으며, 실행을 시도하면 ActivityNotFoundException 또는 유사한 예외가 발생합니다. 구성 요소는 application 태그 내에 등록되며, 순서는 작동에 영향을 미치지 않습니다.
activity 태그는 애플리케이션의 화면을 등록합니다. exported 속성은 다른 애플리케이션이 이 Activity를 실행할 수 있는지 결정합니다. Android 12부터 intent-filter가 있는데 exported가 없으면 빌드 오류가 발생합니다 — 이는 보안 요구 사항입니다. 진입점은 action MAIN과 category LAUNCHER가 있는 intent-filter를 통해 설정됩니다. 각 Activity는 고유한 android:name을 가져야 하며, 이는 전체 또는 상대 클래스 이름과 일치해야 합니다.
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
service 태그는 백그라운드 서비스를 정의합니다. Android 8부터 백그라운드 서비스에는 엄격한 제한이 있습니다: foreground service는 사용자에게 표시되는 아이콘이 있는 알림이 필수이며, bound service는 연결된 클라이언트가 있을 때만 작동합니다. 알림 없이 백그라운드에서 실행되는 서비스는 애플리케이션이 백그라운드 모드로 전환된 후 몇 분 내에 시스템에 의해 자동으로 종료됩니다. 장기 작업에는 Service 대신 WorkManager를 사용하세요.
<service
android:name=".SyncService"
android:exported="false"
android:foregroundServiceType="dataSync" />
receiver 태그는 시스템 또는 사용자 정의 브로드캐스트 메시지의 수신기를 선언합니다. Android 8부터 대부분의 암시적 브로드캐스트는 더 이상 매니페스트에 정적으로 선언된 수신기로 전달되지 않습니다. 대신 코드에서 Context.registerReceiver를 통해 수신기를 동적으로 등록하는 것이 좋습니다. BOOT_COMPLETED와 같은 일부 시스템 브로드캐스트는 예외로, 여전히 매니페스트에 정적 등록이 필요합니다.
<receiver
android:name=".ConnectivityReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Android의 각 위험 권한은 매니페스트에서 uses-permission 태그를 통해 선언해야 합니다. Android 6부터 위험 권한은 사용자와의 대화 상자를 통해 런타임에 요청되지만, 매니페스트 선언은 여전히 필수입니다. 선언 없이 requestPermissions 메서드를 호출하면 SecurityException이 발생합니다. INTERNET 및 ACCESS_NETWORK_STATE와 같은 일반 수준 권한은 설치 시 자동으로 부여됩니다.
| 권한 | 용도 |
|---|---|
| CAMERA | 사진 및 비디오를 위한 기기 카메라 접근 |
| ACCESS_FINE_LOCATION | GPS 및 네트워크를 통한 정확한 위치 |
| RECORD_AUDIO | 기기 마이크로 오디오 녹음 |
| READ_CONTACTS | 전화번호부에서 연락처 읽기 |
| POST_NOTIFICATIONS | Android 13+에서 알림 보내기 |
uses-permission-sdk-23 태그는 Android 6.0+에서만 필요한 권한을 지정합니다. 이를 통해 존재하지 않는 권한을 요청하지 않으면서 이전 버전과의 호환성을 유지할 수 있습니다. 예를 들어 POST_NOTIFICATIONS는 Android 13+에서만 사용 가능하므로, uses-permission-sdk-33을 통해 지정해야 이전 기기에서 알 수 없는 권한 오류가 발생하지 않습니다. uses-permission의 maxSdkVersion 속성은 새 Android 버전에서 애플리케이션을 업데이트할 때 불필요한 권한을 자동으로 철회할 수 있게 합니다.
일반 수준 권한(INTERNET, ACCESS_NETWORK_STATE)은 설치 시 자동으로 부여되며 런타임 요청이 필요하지 않습니다. 이들도 uses-permission을 통해 선언되지만 사용자에게 대화 상자로 표시되지 않습니다. 다른 애플리케이션의 앱 구성 요소 접근을 제어하기 위해 permission-protected components 메커니즘이 사용됩니다: Activity 또는 Service 수준에서 사용자 정의 권한을 지정할 수 있으며, 외부에서 구성 요소를 호출할 때 시스템이 확인합니다. 이는 프로세스 간 통신을 위한 추가 보안 계층을 제공합니다.
매니페스트의 intent-filter 태그는 구성 요소가 처리할 수 있는 암시적 인텐트를 선언합니다. 이것은 Android가 시스템 또는 사용자 정의 작업을 애플리케이션과 연결하는 메커니즘입니다. Intent filter는 세 가지 요소로 구성됩니다: action(작업), category(카테고리), data(데이터). 세 가지 모두 구성 요소가 받을 인텐트를 정확히 설명하기 위해 조합될 수 있습니다. 시스템은 가장 구체적인 필터를 기반으로 적합한 구성 요소를 선택합니다.
<activity android:name=".DeepLinkActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="itsectr.com"
android:pathPrefix="/app" />
</intent-filter>
</activity>
autoVerify 속성은 Android App Links 확인을 활성화합니다: 시스템이 도메인 소유권을 확인하기 위해 서버에 연결합니다. 확인 없이 딥링크는 표준 선택 대화 상자를 통해 작동하며, 사용자가 링크를 열 앱을 선택합니다. 성공적인 확인 후 링크는 대화 상자 없이 직접 애플리케이션에서 열립니다. Google Search Console도 autoVerify를 사용하여 딥 링크를 인덱싱하고 검색 결과에 표시합니다.
action.VIEW와 DEFAULT 및 BROWSABLE 카테고리가 있는 필터는 브라우저, 이메일 및 기타 애플리케이션의 링크를 처리합니다. 이것이 Android에서 딥링크를 구현하는 주요 메커니즘입니다. myapp://와 같은 사용자 정의 URL 스킴을 지원하려면 host 없이 scheme만 지정하면 됩니다. 그러나 Google은 사용자 정의 스킴 대신 HTTPS 딥링크를 권장합니다. 더 안전하고 추가 권한이 필요하지 않기 때문입니다. 사용자 정의 스킴은 동일한 스킴을 등록한 모든 애플리케이션이 가로챌 수 있습니다.
루트 manifest 태그에는 패키지, 버전 및 SDK 속성이 포함됩니다. application 태그는 테마, 아이콘, 레이블 및 디버깅 플래그와 같은 전역 설정을 저장합니다. manifest 속성은 패키지 수준에서 버전 관리를 설정하고, application 속성은 애플리케이션의 전체적인 모양과 동작을 정의합니다. 값은 @-구문을 통한 리소스 참조 또는 문자열 리터럴일 수 있습니다.
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itsectr.myapp"
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="34" />
<application
android:label="MyApp"
android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.MyApp"
android:supportsRtl="true"
android:allowBackup="true">
<!-- 애플리케이션 구성 요소 -->
</application>
</manifest>
application 내부의 meta-data 태그는 임의의 키-값 쌍을 저장할 수 있습니다. 이는 서드파티 라이브러리 구성에 유용합니다: API 키, 엔드포인트 주소 및 기능 플래그. meta-data의 데이터는 런타임에 PackageManager.getApplicationInfo().metaData를 통해 접근할 수 있습니다. 예를 들어 Firebase 및 Google Maps는 소스 코드에 하드코딩하지 않고 접근 키를 전달하기 위해 meta-data를 사용합니다. 키는 매니페스트에서 설정되며 빌드 플레이버에 따라 다를 수 있습니다.
android:extractNativeLibs 속성은 APK에서 네이티브 라이브러리 추출을 제어합니다. targetSdk 34+ 애플리케이션의 경우 이 속성을 명시적으로 지정해야 하며, 그렇지 않으면 INSTALL_FAILED_INVALID_APK 오류로 빌드가 실패할 수 있습니다. extractNativeLibs=false이면 네이티브 라이브러리가 압축 해제 없이 APK 내부에 남아 설치된 애플리케이션 크기는 줄어들지만 라이브러리 로딩 시간이 증가합니다. 대부분의 최신 애플리케이션에서는 사용자 디스크 공간을 절약하기 위해 extractNativeLibs=false를 권장합니다.
android:networkSecurityConfig 속성은 네트워크 보안 구성 파일을 지정할 수 있게 합니다. 이는 targetSdk 28+ 애플리케이션에서 특히 중요합니다. HTTP 트래픽이 기본적으로 차단되기 때문입니다. 구성 파일은 신뢰할 수 있는 인증서, HTTP 연결 도메인 및 인증서 고정 규칙을 정의합니다. 이는 더 이상 사용되지 않는 android:usesCleartextTraffic 속성을 대체하며 OS 수준에서 연결 보안 관리의 유연한 메커니즘을 제공합니다.
android:largeHeap 속성은 애플리케이션의 증가된 힙 크기를 요청합니다. 기본적으로 Android는 각 애플리케이션에 기기 및 OS 버전에 따라 제한된 메모리를 할당합니다. 애플리케이션이 무거운 이미지, 비디오 또는 대용량 데이터 세트를 다루는 경우 largeHeap이 OutOfMemoryError를 방지할 수 있습니다. 그러나 이 속성을 남용하면 해롭습니다: 메모리를 많이 소비하는 애플리케이션은 리소스 부족 시 시스템에 의해 더 빨리 종료됩니다. 프로파일링 후 필요성이 확인된 경우에만 largeHeap을 사용하세요.
자주 묻는 질문
Android 12부터 intent-filter가 있는데 exported 속성이 없으면 빌드 오류가 발생합니다. 시스템은 intent-filter가 있는 각 구성 요소의 가시성을 명시적으로 요구합니다 — 이는 다른 애플리케이션이 구성 요소를 우발적으로 여는 것을 방지하기 위한 보안 조치입니다. intent-filter가 없는 Activity의 exported는 기본값이 false입니다.
네, 하지만 런처에 여러 개의 앱 아이콘이 표시됩니다. MAIN/LAUNCHER가 있는 각 Activity는 별도의 진입점이 됩니다. 이는 앱의 다른 섹션으로 바로 가기를 만드는 데 사용됩니다. 예를 들어 설정이나 새 항목 만들기로 바로 이동합니다. 각 아이콘은 해당 Activity를 직접 엽니다.
Android는 라이브러리의 매니페스트를 기본 애플리케이션 매니페스트와 병합합니다. 속성 충돌 시 tools:replace 또는 tools:node="merge"를 사용하여 해결합니다. 이 메커니즘은 자동입니다: Gradle을 통해 라이브러리를 추가하면 해당 매니페스트가 기본 매니페스트와 병합됩니다. 라이브러리의 속성을 취소하거나 교체하려면 tools:node="remove" 또는 tools:replace="attributeName"을 사용하세요.
일반적인 원인: 매니페스트에서 uses-permission으로 권한을 선언하지 않음, 일반 권한 사용(런타임 요청 없음), 사용자가 “다시 묻지 않음”을 선택하여 권한이 영구적으로 거부됨, 또는 targetSdkVersion이 23 미만으로 설치 시 권한이 요청됨. 진단을 위해 매니페스트와 adb logcat 로그를 확인하세요.
android:debuggable 속성은 ADB를 통한 애플리케이션 디버깅을 활성화합니다. Google Play 릴리스 빌드에서는 false여야 합니다. 릴리스 빌드에서 debuggable=true이면 공격자가 ADB를 통해 애플리케이션에 연결하여 데이터를 읽고 임의 코드를 실행할 수 있습니다. Google Play는 debuggable=true인 빌드 게시를 자동으로 차단합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.