들어가며
안드로이드 개발을 하다보면 AndroidManifest.xml 파일을 손보는 경우가 생깁니다. 주로 새 화면(Activity)을 추가하거나, 권한을 설정하거나, 테마 및 화면 관련 설정 등이 필요할 때 Manifest 파일을 수정할 것입니다.
그러나 필자는 이 파일이 정확히 무슨 역할을 하고, 또 여기서 무엇을 더 할 수 있는지 자세히 알아보려한 적이 없었던 것 같습니다.
Manifest 파일은 모든 앱에 필수적이며, 앱의 기본적인 정보를 담고 있는 중요한 파일이기 때문에, 안드로이드 개발자라면 이 파일에 대한 개념을 알아둘 필요가 있습니다.
이번 포스팅에서는 AndroidManifest의 역할과 기능에 대해 자세히 알아보겠습니다.
AndroidManifest란?
App manifest overview | App architecture | Android Developers
앱 매니페스트 개요 | App architecture | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 앱 매니페스트 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 모든 앱 프로젝트는 프로젝트 소
developer.android.com
AndroidManifest(이하 매니페스트라 칭합니다)는 Google Play, Android 빌드 도구, Android OS에게 앱에 대한 필수 정보들을 넘겨주는 역할을 합니다.
여기서 말하는 앱의 필수 정보들은 크게 아래와 같습니다.
- 앱이 가지고 있는 컴포넌트 종류와 속성
- 앱에서 필요한 권한 목록
- 앱이 사용하는 하드웨어 및 소프트웨어 기능 종류
매니페스트는 앱의 메타데이터 — 앱이 어떤 화면, 서비스와 같은 구성요소를 가지고 있는지, 필요한 권한은 무엇이고 기기 및 OS 내부의 어떤 기능을 사용하는지에 대한 전반적인 정보 — 를 시스템과 Play Store에 제공해줍니다. 비유하자면, 앱의 신상 정보를 담고있는 신분증 역할을 한다고 이해하셔도 좋을 것 같네요.
매니페스트 파일은 아래처럼 구성되어 있습니다.
<manifest package="com.example.app">
<uses-feature android:name="android.hardware.camera.any"
android:required="false"/>
<uses-permission android:name="android.permission.CAMERA"/>
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="geo"/>
</intent>
</queries>
<application android:allowBackup="true"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".PlaybackService"
android:exported="false"
android:foregroundServiceType="mediaPlayback"/>
</application>
</manifest>
AndroidManifest가 담는 정보
어떤 정보들이 매니페스트에 담기는지 전반적으로 살펴봅시다.
컴포넌트 정보
안드로이드 4대 컴포넌트(Activity, Service, Broadcast Receiver, Content Provider)에 대한 정보가 이곳에 명시됩니다.
우리가 평소에 Activity, Service 등을 만들어 구현하고 해당 컴포넌트를 매니페스트 파일에 추가했던 작업이 바로 이것입니다.
개발자가 만든 각 구성요소들은 반드시 그에 상응하는 XML 구성요소로 추가되어야 합니다.
- Activity 클래스 → <activity>
- Service 클래스 → <service>
- BroadcastReceiver 클래스 → <receiver>
- ContentProvider 클래스 → <provider>
매니페스트 파일에 모든 구성요소를 명시하지 않으면, 시스템은 해당 컴포넌트를 실행할 수 없습니다.
컴포넌트 정보는 아래와 같이 등록할 수 있습니다.
<manifest ... >
<application ... >
...
<activity android:name="com.example.myapp.presentation.MainActivity" ... />
...
</application>
</manifest>
- 등록할 컴포넌트에 대응하는 XML 구성요소를 추가합니다.
- name 속성으로 해당 컴포넌트 클래스 경로를 넣습니다.
- 클래스의 패키지 경로가 들어가야합니다.
- 만약 앱 패키지가 com.example.myapp 이고, MainActivity가 presentation 패키지(또는 모듈) 내에 위치한다면 패키지 경로는 다음과 같습니다. → com.example.myapp.presentation.MainActivity
- name 속성에 . 이 먼저 붙으면 build.gradle 파일의 namespace에 정의된 패키지 경로로 설정됩니다.
- build.gradle 에 설정된 namespace가 com.example.myapp 라면, 패키지 경로를 아래처럼 둘 수 있습니다.
<activity android:name=".presentation.MainActivity" />
인텐트 필터
앱의 각 구성요소가 어떤 인텐트를 받아들일 수 있는지 나타냅니다.
인텐트란 무엇을 할 것인지를 담은 일종의 “메시지”이고, 앱의 Activity, Service, BroadcastReceiver가 어떤 인텐트에 의해 실행될 수 있는지 명시하는 것이 바로 인텐트 필터입니다. 매니페스트에 인텐트 필터를 작성하여, 수행하고자 하는 동작(action)과 동작에 필요한 데이터(data), 그 동작을 수행하는 컴포넌트의 유형(category)을 명시할 수 있습니다.
인텐트에 대해 더 자세히 알고싶다면 아래 공식 문서를 참고해주세요.
인텐트 및 인텐트 필터 | App architecture | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 인텐트 및 인텐트 필터 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Intent는 다른 앱 구성요소에서
developer.android.com
링크 열기, 컨텐츠 공유와 같이 응답할 수 있는 인텐트 종류를 이 곳 매니페스트에 명시해두면, 다른 앱이 개발자의 앱과 상호 작용할 수 있도록 도와줍니다.
아래 예시와 같이, <activity> , <service> , <receiver> 구성요소 안에 <intent-filter> 구성요소를 정의하여 인텐트 필터를 추가할 수 있습니다.
<manifest ... >
<application ... >
<activity
android:name=".presentation.MainActivity"
android:exported="true"
... >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="example" />
</intent-filter>
</activity>
</application>
</manifest>
- <intent-filter> 를 사용할 때는 android:exported 속성을 반드시 함께 설정해야합니다. 외부 다른 앱에서 접근할 수 있도록 하려면 true로, 아니라면 false로 설정합니다.
- <intent-filter> 안에 <action> , <data> , <category> 구성요소를 명시할 수 있습니다.
권한
매니페스트에는 앱이 요청하는 권한을 명시합니다.
안드로이드의 앱은 민감할 수 있는 사용자 데이터에 접근할 때, 또는 시스템 기능에 접근할 때 필요한 권한을 요청해야합니다.
- 민감한 사용자 데이터 : 사진, 위치 정보, 연락처 등 사용자의 개인 정보와 관련된 데이터
- 시스템 기능 : 카메라, 인터넷 접속 등 시스템과 기기에서 제공하는 기능
권한을 요청하지 않으면 해당 기능에 접근하려는 시도가 실패합니다.
아래는 SMS를 보내는 권한을 명시하는 예시입니다.
<manifest ... >
<uses-permission android:name="android.permission.SEND_SMS"/>
...
</manifest>
- <uses-permission> 구성 요소를 사용해 권한을 명시합니다.
- 안드로이드 시스템에서 제공하는 권한은 고유한 라벨(label)이 있습니다. 필요한 권한은 android.permission 에서 찾을 수 있습니다.
TMI : 만약 앱에서 커스텀 권한을 만들어 사용한다면, <permission> 구성 요소로 커스텀 권한을 명시할 수 있습니다.
<manifest ... >
<permission
android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
android:label="@string/perm_label_deadlyActivity"
android:description="@string/perm_description_deadlyActivity"
android:permissionGroup="android.permission_group.CONTACTS"
android:protectionLevel="dangerous" />
...
</manifest>
권한에 대한 더 자세한 정보는 공식 문서를 참고해주세요.
디바이스 호환성
앱에 필요한 디바이스 기능 목록을 명시합니다.
매니페스트 파일에는 앱에 필요한 하드웨어, 소프트웨어 기능과 앱이 호환되는 기기 유형을 선언할 수 있습니다.
매니페스트에서 선언한 이 기능 목록으로 앱의 기기 호환성이 결정됩니다. Play Store는 앱에 필요한 기능이나 시스템 버전을 제공하지 않는 기기에서는 앱 설치를 제한합니다.
매니페스트에서 앱이 사용하는 하드웨어, 소프트웨어 기능을 선언할 때는 <uses-feature> 구성요소를 사용합니다. 만약 앱에서 카메라 기능이 꼭 필요한 경우 아래처럼 선언할 수 있습니다.
<manifest ... >
<uses-feature
android:name="android.hardware.camera.any"
android:required="true" />
...
</manifest>
- name 속성에 하드웨어 및 소프트웨어 기능을 설정합니다.
- 여기에 명시하는 값을 기능 상수라고 하며, android.hardware 에서 찾을 수 있습니다.
- required 속성은 해당 기능이 앱에 필수인지를 결정짓습니다.
- 만약 카메라를 사용하지만 꼭 필요한 기능은 아닌 경우, false로 설정할 수 있습니다.
- 위 예시에서 카메라 기능이 없는 기기에서는 지원할 수 없다고 판단해, Play Store가 앱을 필터링 합니다.
그러나 사실 특정 기능의 경우, <uses-feature> 없이 권한을 설정해도 기능을 사용할 수 있습니다.
즉, 권한을 설정하면 관련 기능이 암시적으로 선언됩니다. 이는 이전 버전을 타겟팅하는 레거시 앱의 호환성을 올바르게 지원하기 위함 입니다.
일부 기능(대표적으로 Blutooth API)의 경우 API가 먼저 추가되고, 이후에 기능 상수가 추가되었습니다. 때문에 예전 세대(레거시) 앱은 해당 API를 사용함에도 <uses-feature>로 요구사항을 선언할 수 없었습니다. 이런 앱이 지원하지 않는 기기에도 노출되는 문제를 막기 위해 구글 Play Store는 특정 하드웨어 관련 권한이 선언되면 그 하드웨어 피처를 “필수”로 간주해 필터링에 반영합니다.
대표적인 예로, 카메라나 위치 정보의 경우 <uses-permission> 으로 권한을 설정하여도 Play Store가 암시적으로 카메라 또는 위치 정보(GPS)를 필요로 하다고 판단합니다.
<manifest ... >
<uses-permission android:name="android.permission.CAMERA"/>
...
<!-- 카메라 권한이 설정되어 있어, 기능을 명시하지 않아도 Google Play가 암시적으로 선언
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
-->
...
</manifest>
하지만 권한을 설정하여도 <uses-feature> 을 통해 기능을 명시하는 것이 좋고, 기능에 관한 권한을 설정했더라도 해당 기능이 필수가 아니라면 android:required=”false” 을 통해 암시적 기능 필터링을 피하는 것이 좋습니다.
<manifest ... >
<uses-permission android:name="android.permission.CAMERA"/>
...
<!-- 카메라 권한이 설정되어도 기능을 명시, required="false"로 암시적 필터링 회피 -->
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
...
</manifest>
주요 구성 요소와 특징
매니페스트 파일을 구성하는 주요 구성 요소들을 간단하게 살펴봅니다. 공식 문서를 바탕으로 알아보았습니다.
앱 매니페스트 개요 | App architecture | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 앱 매니페스트 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 모든 앱 프로젝트는 프로젝트 소
developer.android.com
<manifest>
앱의 매니페스트 루트 요소입니다. 반드시 하나의 <application>을 포함해야하며, package와 xmlns:android 네임스페이스를 명시해야 합니다.
- package: 앱의 애플리케이션 ID(패키지 이름). 변경 시 기존 앱과 다른 앱으로 간주됩니다.
- android:versionCode / android:versionName: 내부/표시용 버전(현대 빌드에선 Gradle로 관리하는 경우가 많지만 속성 자체는 존재)
- android:installLocation: 설치 위치 정책(internalOnly / auto / preferExternal)
- android:sharedUserId(폐지 예정), android:sharedUserMaxSdkVersion: UID 공유 관련 설정이지만 폐지될 예정이므로 사용을 지양합니다.
<application>
앱 전체 정보를 나타내며, 하위에 각 컴포넌트 요소를 포함합니다. 일부 속성은 하위 컴포넌트의 기본값이 됩니다.
- android:name: 커스텀 Application 서브클래스
- android:label/android:icon/android:theme: 앱 전역 라벨/아이콘/테마(컴포넌트에서 재정의 가능)
- android:allowBackup: 백업/복원 참여 여부(기본 true)
- android:usesCleartextTraffic: 평문 HTTP 허용 여부(API 28+ 기본 false)
- android:networkSecurityConfig: 네트워크 보안 설정 XML 지정
- android:process/android:permission: 기본 프로세스/권한 기본값 지정
<activity>
화면 UI를 담당하는 Activity를 선언합니다. 선언되지 않은 액티비티는 실행되지 않습니다.
- android:name: 클래스 이름(필수)
- android:exported: 외부에서 시작 가능 여부(인텐트 필터 유무에 따라 기본값 달라짐). Android 12(API 31)+에서 인텐트 필터가 있으면 명시가 필수
- android:launchMode: 인스턴스 생성/재사용 동작
- android:taskAffinity/android:allowTaskReparenting: 태스크 소속/재배치
- android:theme/android:label/android:icon: UI 표시 관련 속성
<service>
UI 없는 백그라운드 작업이나 바인딩 API를 제공하는 Service를 선언합니다.
- android:name(필수), android:enabled
- android:exported: 외부 앱의 시작/바인딩 허용 여부. Android 12(API 31)+에서 인텐트 필터가 있으면 명시가 필수
- android:foregroundServiceType: 포어그라운드 서비스 용도 지정(예: location, mediaPlayback 등)
- android:stopWithTask: 태스크 제거 시 서비스 중지
- android:isolatedProcess: 격리 프로세스에서 실행
<receiver>
브로드캐스트를 수신하는 BroadcastReceiver를 선언합니다. 정적 선언 또는 런타임 등록 모두 가능합니다.
- android:name(필수), android:enabled
- android:exported: 외부 브로드캐스트 수신 허용. Android 12(API 31)+에서 인텐트 필터가 있으면 명시가 필수
- android:permission: 특정 권한 보유자만 전송 가능하게 제한
참고 : Android 8.0(API 26)+에선 암시적 브로드캐스트 등록에 제한이 있습니다.
<provider>
앱의 데이터를 외부에 제공하는 ContentProvider를 선언합니다.
- android:authorities(필수): 고유 권한자(authority) 문자열
- android:exported: 외부 접근 허용 여부 및 기본값 규칙
- android:readPermission/android:writePermission/android:permission: 접근 제어
- android:grantUriPermissions + <grant-uri-permission>/FLAG_GRANT_*: 일시적 URI 권한 위임
- android:directBootAware: Direct Boot 단계에서 접근 가능 여부
<intent-filter>
컴포넌트가 처리할 수 있는 인텐트를 선언하여 외부 노출/런처 진입점을 정의합니다.
- 하위 요소: <action>, <category>, <data>
- ACTION/CATEGORY/데이터(URI, MIME)로 매칭
<action> / <category> / <data>
인텐트 필터의 구성 요소입니다. 처리할 동작/카테고리/데이터 스펙을 세부 지정합니다.
- <action android:name="…">
- <category android:name="…">
- <data …> : mimeType 또는 scheme://host[:port]/path* 등으로 URI/MIME 패턴 지정
<meta-data>
컴포넌트나 애플리케이션에 키-값 메타데이터를 추가합니다. 코드에서 PackageItemInfo.metaData로 조회할 수 있습니다.
- android:name/android:value 또는 android:resource로 값 지정
- 사용 위치: <application>, <activity>, <service>, <receiver>, <provider>, <activity-alias>
<uses-permission>
앱이 요청(또는 설치 시 자동 승인되는 종류의) 권한을 선언합니다. 일부 하드웨어 관련 권한은 Google Play가 하드웨어 요구 사항으로 간주하여 기기 필터링에 반영합니다. (그러나 가능한 한 <uses-feature>로 명시를 권장합니다.)
- android:name: 요청할 권한 이름(플랫폼/타 앱/커스텀 권한)
- android:maxSdkVersion: 특정 API 레벨 이하에서만 권한이 필요할 때 제한
<uses-permission-sdk-23>
API 23+에서만 권한을 요청하고, 그 미만에서는 해당 권한 없이 기능을 비활성화하려 할 때 사용합니다.
- android:name, android:maxSdkVersion
<uses-feature>
앱이 필요로 하거나(또는 선택적으로 사용하는) 하드웨어/소프트웨어 피처를 선언합니다. Google Play의 기기 호환성 필터링 근거가 됩니다.
- android:name: 피처 상수 이름(예: android.hardware.camera)
- android:required: 기본 true, 선택적 사용이면 false.
- android:glEsVersion: OpenGL ES 요구 버전 지정
<uses-sdk>
앱이 지원하는 플랫폼 범위(최소/목표/최대 API 레벨)를 선언합니다. 근래에는 Gradle(build.gradle)에서의 설정을 우선시 합니다.
- android:minSdkVersion / android:targetSdkVersion / android:maxSdkVersion
<queries>
앱이 조회할 의도가 있는 다른 앱/패키지/프로바이더를 선언합니다.
- 하위 구성 요소 : <package>, <intent>, <provider>
- 위 구성 요소로 가시성 필요성을 기술합니다.
<permission>
다른 앱이 사용(또는 본인 앱 내에서 자체 보호)할 커스텀 권한을 정의합니다. 보호 수준(normal/dangerous/signature …)과 그룹을 설정할 수 있습니다.
- android:name: 권한 이름(보통 my.package.permission.XYZ)
- android:protectionLevel: 권한 보호 수준 및 플래그
- android:permissionGroup: 권한 그룹에 소속
<activity-alias>
기존 액티비티에 대한 별칭을 만들어, 별도의 인텐트 필터/런처 아이콘/권한 등으로 노출을 제어합니다.
- android:targetActivity(필수)
- android:exported, android:permission 등(일부는 <activity> 속성의 부분집합)
<instrumentation>
앱에 대해 특별한 모니터링/테스팅 코드를 지정합니다. 일반적입 앱 개발에선 드물게 사용됩니다.
- android:name, android:targetPackage 등으로 테스트/러너를 지정합니다.
마치며
지금까지 AndroidManifest.xml에 대해서 살펴보았습니다. 생각보다 더욱 많은 정보를 담고 있었고, 또 여러 가지 역할을 해주고 있었습니다.
매니페스트 파일의 역할과 구성을 잘 이해하면 앱과 시스템 간 관계, 앱과 앱 사이의 상호작용 등 안드로이드의 전반적인 그림을 이해하는데 많은 도움이 될 것 같습니다.
'개발 > Android' 카테고리의 다른 글
| [Android] GitHub Actions로 CI에서 UI 테스트 수행하기 (0) | 2025.11.14 |
|---|---|
| [Android] GitHub Actions로 QA용 CD 구축하기 - Firebase 활용 (0) | 2025.08.03 |
| [Android] Compose에서 Pinch Zoom 구현하기 (0) | 2025.06.13 |
| [Android] GitHub Actions로 CI 적용하기 - 간단 가이드 (0) | 2025.04.02 |
| [Android] Compose 상태 관리 심화 (0) | 2025.02.15 |
