매니페스트 ( Manifest)
모든 앱 프로젝트는 프로젝트 Source Set 루트에 `AndroidManifest.xml` 파일이 있어야 한다.
안드로이드 개발자 문서를 보면 "매니페스트 파일은 Android 빌드 도구, Android 운영체제 및 Google Play에 앱에 관한 필수 정보를 설명합니다" 라고 적혀있다. 글로만 보면 정확히 매니페스트 파일이 어떤 파일인지 감이 오지 않는다. 해당 포스팅은 안드로이드 매니페스트의 컴포넌트와 함께 정확히 무엇을 하는 파일인지 살펴보는 시간을 가질 것이다.
매니페스트 파일에는 많은 정보를 담을 수 있지만. 다음 4가지를 꼭 선언해야한다.
- 앱의 패키지 이름
- 앱의 구성 요소
- 앱이 액세스하기 위해 필요한 권한
- 앱에 필요한 하드웨어 및 소프트웨어 기능
위 4가지에 대해 자세히 살펴보자.
1. 패키지 이름과 애플리케이션 ID
매니페스트 파일의 루트 요소는 앱의 패키지 이름에 대한 특성이 필요하다.
예를 들어 패키지 이름이 "com.example.rc_1'인 mannifest파일을 생성해보자.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rc_1"
android:versionCode="1"
android:versionName="1.0" >
...
</manifest>
그렇다면 이 패키지 이름을 어디에 사용할까?
Android 빌드 도구가 package 특성을 사용하는 목적은 두 가지이다.
- R.java 클래스가 생성되고 접근하는데 사용하는 네임스페이스로 적용된다.
- 빌드 도구는 이 이름을 사용하여 매니페스트 파일에 선언되어 있는 상대 클래스 이름을 확인한다. <activity android:name=".MainActivity">로 선언된 액티비티가 "com.example.rc_1.MainActivity"를 가리키게 된다.
이와 같이, 매니페스트의 package 속성에 있는 패키지 이름은 프로젝트의 기본 패키지 이름과 항상 일치해야 한다. 물론 프로젝트에 다른 하위 패키지가 있을 수 있지만 하위 패키지의 경로가 아닌 package 속성의 네임스페이스를 사용하여 R 클래스가 생성된다.
그러나 APK가 컴파일되고 나면 빌드 도구가 package의 값을 build.gradle 파일에 있는 applicationId로 대체해버린다. 그 이유는 앱을 시스템과 Googel play에서 식별할 수 있게 package 최종값은 전체적으로 고유해야하기 때문이다.
매니페스트의 package 이름과 build.gradle 파일의 applicationId를 구분하면 혼란스러울 수 있다.
2. 앱 구성요소
앱에서 생성하는 각각의 구성 요소에 대해 살펴보자. 이러한 구성 요소를 사용하기 위해서는 매니페스트 파일에 등록을 해주어야 한다. 등록을 위해서 다음과 같은 XML 요소를 선언해야 한다.
- <activity> : Activity의 하위 클래스, 액티비티의 경우
- <service> : Service의 하위 클래스, 서비스의 경우
- <receiver> : BroadcastReceiver 하위 클래스, Broadcast Receiver
- <provider> : ContentProvider 하위 클래스, 콘텐츠 제공자의 경우
매니페스트 파일에서 xml요소를 선언하지 않으면 시스템에서 컴포넌트를 실행할 수 없다.
하위 클래스의 이름은 완전한 패키지 이름을 사용하여 name 특성으로 지정해야 한다. 아래는 Activity 하위 클래스를 선언한 예시이다.
<manifest ... >
<application ... >
<activity android:name="com.example.rc_1.MainActivity" ... >
</activity>
</application>
</manifest>
여기서 name을 앞에서 package 속성에서 얻어낸 네임스페이스로 대체해서 사용할 수 있다.
<manifest ... >
<application ... >
<activity android:name=".MainActivity" ... >
</activity>
</application>
</manifest>
name에 .을 찍으면 패키지 속성에서 얻어낸 네임스페이스로 경로를 해석할 수 있다.
인텐트
앱 액티비티, 서비스, Broadcast Receiver는 인텐트로 활성화된다. 인텐트는 실행할 작업을 설명하는 Intent 객체로 정의되는 메시지이다. 즉, 어떤 행동을 수행할 지 명령이나 작업에 필요한 데이터를 포함한다.
앱이 인텐트를 시스템에 발행하면 시스템은 각 앱의 매니페스트 파일에 선언된 인텐트 필터로 앱 구성 요소를 찾는다. 시스템은 일치하는 구성 요소의 인스턴스를 시작하고 해당 구성 요소에 Intent 객체를 전달한다. 만약 여러 개의 앱이 인텐트를 처리할 수 있을 경우 사용자는 해딩 인텐트를 어떤 앱으로 넘길지 선택할 수 있다.
아이콘 및 레이블
해당 앱 구성 요소에 대해 사용자에게 표시하기 위한 Icon과 label 특성이 있다.
상위 요소에 설정된 아이콘과 레이블은 모든 하위 요소에 대해 기본 icon과 label 값이 된다. xml은 트리 구조이기때문에 부모-자식 관계가 생긴다. 이때 상위 요소에 설정된 아이콘이 부모가 되어 자식요소가 icon과 label이 설정되지 않았다면 부모의 설정된 icon이 기본 값으로 설정되게 된다. 따라서 <application> 요소에 icon과 label을 설정한다면 모든 액티비티에 대한 기본 icon과 label 로 설정된다.
3. 권한
Android 앱은 민감한 사용자 데이터(연락처, SMS) 또는 특정 시스템 기능(카메라, 인터넷 액세스)에 접근하기 위한 권한을 요청해야 한다.
각 권한은 고유한 레이블로 식별된다. 예를 들어 SMS 전송에 대한 권한을 요청하기 위해서는 Manifest 파일에 다음과 같이 설정해야 한다.
<manifest ... >
<uses-permission android:name="android.permission.SEND_SMS"/>
...
</manifest>
Android 6.0(API level 23) 부터 사용자는 일부 앱 권한을 승인하거나 거절할 수 있게 된다. 그러나 앱이 어떤 안드로이드 버전을 지원하든 매니페스트에서 `<uses-permission>`요소로 모든 권한 요청을 선언해야 한다. 권한이 부여되면 앱이 보호된 기능을 사용할 수 있지만 권한이 부여되지 않으면 시스템 기능에 접근을 실패한다.
4. 기기 호환성
안드로이드에서는 플랫폼 API를 통해 앱에서 활용할 수 있는 다양한 기능을 지원한다. 일부 기능은 하드웨어 기반(예: 나침반 센서)이며 일부는 소프트에어 기반(예: 앱 위젯)이다.
매니페스트 파일에서는 앱에 필요한 하드웨어 또는 소프트웨어 기능을 선언할 수 있다. 예를 들어 카메라 앱을 만들 경우에 카메라가 필수이니 카메라가 있는 기기에서만 Play Store에서 앱이 다운로드 될 수 있도록 명시하는 것이다. 이처럼 매니페스트에 앱과 호환되는 기기 유형을 선언하고 시스템이 제공하지 않는 기기에는 앱 설치를 허용하지 않을 수 있다.
어느 기기가 앱과 호환되는지 정의하는 매니페스트 태그가 여러 가지 있다. 가장 일반적으로 사용하는 태그 몇가지를 살펴보자.
- <uses-feature> : 기기 기능에 따라 앱의 사용 가능 여부 판단
이 요소를 사용하여 앱에 필요한 하드웨어 및 소프트웨어 기능을 선언할 수 있다. 예를 들어 나침반 센서가 없는 기기에서 앱이 기본적인 기능을 실행할 수 없다면, 다음과 같은 매니페스트 태그를 이용하여 선언할 수 있다.
<manifest ... >
<uses-feature android:name="android.hardware.sensor.compass"
android:required="true" />
...
</manifest>
- <uses-sdk> : 안드로이드 플랫폼 최소 버전 확인
안드로이드는 다양한 버전의 플랫폼이 있다. 하지만 안드로이드 OS가 발전함에 따라 API가 추가되는 경우도 있기 때문에 이전 버전의 OS로 앱을 실행했을 경우 API가 없어 다르게 보이거나 동작이 달라질 수도 있다. 따라서 최소 버전을 정의하고 그보다 낮을 경우 다운로드를 하지 못하게 제어해야한다. midSdkVersion으로 최소 버전을 정의한다.
앱이 호환되는 최소 버전을 나타내려면 매니페스트에 <uses-sdk> 태그를 삽입하고 minSdkVersion을 포함해야한다. (현재는 build.gradle에 삽입되어있다 함) 그러나 build.gradle 파일에 선언된 minSdkVersion이 매니페스트 파일을 재정의하기 때문에 min sdk 설정은 매니페스트 파일이 아닌 build.gradle에 선언하는 것이 좋다.
가장 낮은 API 수준은 minSdkVersion으로 설정하고 가장 높은 API 수준은 targetSdkVersion으로 설정한다.
앱이 동작하지 않을 수도 있기에 minSdkVersion을 설정했다. 그런데 왜 높은 수준까지 API를 설정해줄까?개발자의 의도대로 OS동작을 그대로 유지하고 싶을 때 사용한다. 예를 들어 targetSdkVersion이 선언한 버전보다 높은 경우 시스템은 호환성 동작을 활성화할 수 있다. 즉, 개발한 것과 다르게 기능을 수행할 수도 있다는 것이다. 따라서 실행 중인 플랫폼의 API 레벨과 일치하는 targetSdkVersion을 지정하여 그러한 호환성 동작을 비활성화할 수 있다. 만약 설정하지 않을 경우 기본값은 minSdkVersion값과 동일하다. minSdkVersion은 업데이트안해도 되지만 targetSdkVersion은 최신 android버전과 일치하도록 주기적으로 업데이트해야한다.
android {
defaultConfig {
applicationId 'com.example.rc_1'
// Defines the minimum API level required to run the app.
minSdkVersion 15
// Specifies the API level used to test the app.
targetSdkVersion 28
...
}
}
지금까지 매니페스트에 꼭 선언해야 할 4가지 요소에 대해 살펴보았다.
이제부터는 매니페스트 파일에 담기는 갖가지 정보들에 대해 살펴보겠다.
플랫폼 스타일 및 테마 사용
안드로이드에는 앱에 디자인을 적용하는 사용자 환경 테마를 제공한다. 매니페스트 파일에 테마를 선언하면 앱에 적용할 수 있다.
- 대화상자처럼 보이게 할 때
<activity android:theme="@android:style/Theme.Dialog">
- 배경을 투명하게 할 때
<activity android:theme="@android:style/Theme.Translucent">
- /res/values/styles.xml에 정의된 맞춤 테마를 적용할 때
<activity android:theme="@style/CustomTheme">
- 앱 전체에 하나의 테마를 적용할 때 (이때는 `application` 요소에 추가한다.)
<application android:theme="@style/CustomTheme">
파일 규칙
이제는 매니페스트 파일에 포함되는 모든 요소 및 특성에 일반적으로 적용되는 규칙에 대해 살펴보자.
- 요소
<manifest> 및 <application> 요소만 필수적이다. 두 요소는 각각 한번만 실행되어야 하며 다른 요소는 한번만 실행되거나 한 번도 실행되지 않는다. 모든 값은 요소 내의 문자 데이터로서가 아니라 특성을 통해 설정된다.
같은 레벨에 있는 여러 요소는 보통 순서가 지정되지 않는다. 예를 들어 <activity>, <provider> 및 <service> 요소는 어느 순서로든 배치할 수 있다. 하지만 이 규칙에는 두 가지 예외 사항이 있다.
1. <activity-alias> 요소는 <activity> 다음에 와야 한다. 즉, alias가 참조하는 Activity가 먼저 정의되어야 한다.
2. <application>요소는 <manifest> 요소 내부에 있는 마지막 요소여야 한다.
- 특성
루트 <manifest>요소의 몇 가지 특성을 제외하고 모든 특성 이름을 접두사 `android:`로 시작된다.
- 여러 개의 값
둘 이상의 값을 지정할 수 있는 경우 한 요소 안에 여러 값이 나열되지 않고 해당 요소를 반복되게 적어야한다.
- 리소스 값
어떤 특성은 사용자에게 표시되는 값이 설정된다. 이런 특성에 대한 값은 사용자의 기기에 따라 달라질 수 있다. 예를 들어 앱 아이콘의 경우 사용자의 기기 크기에 따라 픽셀을 다르게해주어야한다. 이러한 특성 값은 매니페스트 파일말고 resource 또는 Themes에서 값을 설정해야 한다.
리소스는 다음과 같은 형식의 값으로 표현된다.
@[package:]type/name
앱에서 리소스를 제공할 경우 package이름을 생략할 수 있다. type은 리소스의 유형(string, drawable)이고 name은 특정 리소스를 식별하는 이름이다.
- 문자열 값
특성 값이 문자열인 경우, 문자를 이스케이프 처리하려면 이중 백슬래시(\\)를 사용해야 한다.
매니페스트 파일 예시
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rc_1">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.RC1주차">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
- 참고
[Android] Manifest 개념 잡기
안드로이드 프로젝트에는 반드시 포함되어야 하는 파일이 있습니다. 그건 바로 AndroidManifest.xml 파일입니다. Manifest 파일은 프로젝트의 Source Set의 루트(별도의 설정을 하지 않았다면 src/main)에 위
readystory.tistory.com
'개발 > Android' 카테고리의 다른 글
[안드로이드] 팔레트(palette) 정리 - 1 (0) | 2022.02.07 |
---|---|
[안드로이드] 4대 컴포넌트 (0) | 2022.02.06 |
[안드로이드/Java] JSONArray 파싱하기 (0) | 2021.09.16 |
[안드로이드] Activity 배경 투명으로 하기 (0) | 2021.09.16 |
[안드로이드] Attempt to write to null array 에러 (0) | 2021.09.14 |