매니페스트 파일 관리

이 페이지에서는 매니페스트 병합의 작동 방식과 병합 환경설정을 적용하여 병합 충돌을 해결하는 방법을 설명합니다. 앱 매니페스트 파일에 관한 소개는 앱 매니페스트 개요를 참고하세요.

여러 매니페스트 파일 병합

APK 또는 Android App Bundle 파일에는 AndroidManifest.xml 파일이 1개만 포함되지만 Android 스튜디오 프로젝트에는 주요 소스 세트, 빌드 변형, 가져온 라이브러리에서 제공되는 매니페스트 파일이 다수 포함될 수 있습니다. 앱을 빌드할 때 Gradle 빌드는 모든 매니페스트 파일을 앱에 패키징되는 단일 매니페스트 파일로 병합합니다.

매니페스트 병합 도구는 다음 병합 휴리스틱을 따르고 XML 특별 속성으로 정의한 병합 환경설정을 준수하여 각 파일의 XML 요소를 모두 결합합니다.

팁: 다음 섹션에 설명된 병합된 매니페스트를 사용하여 병합된 매니페스트 결과를 미리 보고 충돌 오류를 찾으세요.

병합 우선순위

병합 도구는 각 매니페스트 파일의 우선순위에 따라 모든 매니페스트 파일을 하나의 파일로 순차 병합합니다. 예를 들어, 매니페스트 파일이 3개가 있다면 그림 1과 같이 우선순위가 가장 낮은 매니페스트가 다음으로 우선순위가 높은 파일로 병합되고, 이렇게 병합된 파일은 가장 우선순위가 높은 파일로 병합됩니다.

그림 1. 3개의 매니페스트 파일을 우선순위가 가장 낮은 파일에서 가장 높은 파일로 병합하는 과정

서로 병합할 수 있는 3가지 기본 매니페스트 파일이 있으며 이러한 파일의 병합 우선순위는 다음과 같습니다(높은 우선순위 순).

  1. 빌드 변형을 위한 매니페스트 파일

    변형에 소스 세트가 여러 개 있다면 매니페스트 우선순위는 다음과 같습니다.

    • 빌드 변형 매니페스트(예: src/demoDebug/)
    • 빌드 유형 매니페스트(예: src/debug/)
    • 제품 버전 매니페스트 (예: src/demo/)

      버전 차원을 사용한다면 매니페스트 우선순위는 각 차원이 flavorDimensions 속성에 나열된 순서(높은 우선순위 순)와 일치합니다.

  2. 앱 모듈의 기본 매니페스트 파일
  3. 포함된 라이브러리의 manifest 파일

    라이브러리가 여러 개 있는 경우 매니페스트 우선순위는 Gradle dependencies 블록에 표시되는 순서와 일치합니다.

예를 들어, 라이브러리 매니페스트는 기본 매니페스트로 병합되고 기본 매니페스트는 빌드 변형 매니페스트로 병합됩니다. 참고로 이는 소스 세트로 빌드에서 설명한 모든 소스 세트의 병합 우선순위와 동일합니다.

중요: build.gradle 파일의 빌드 구성은 병합된 매니페스트 파일에서 대응되는 속성을 모두 재정의합니다. 예를 들어, build.gradle 또는 build.gradle.kts 파일의 minSdk<uses-sdk> 매니페스트 요소에서 일치하는 속성을 재정의합니다. 혼동을 피하려면 <uses-sdk> 요소를 제외하고 build.gradle 파일에만 이러한 속성을 정의합니다. 자세한 내용은 빌드 구성을 참고하세요.

병합 충돌 휴리스틱

병합 도구는 특정 매니페스트의 모든 XML 요소를 또 다른 매니페스트의 상응하는 요소와 논리적으로 연결할 수 있습니다. 매칭 방식에 관한 자세한 내용은 이전 섹션의 병합 우선순위를 참고하세요.

낮은 우선순위의 매니페스트 요소가 높은 우선순위의 매니페스트 요소와 일치하지 않으면 병합된 매니페스트에 추가됩니다. 그러나 일치하는 요소가 있으면 병합 도구는 각 요소의 모든 속성을 동일한 요소로 결합하려고 합니다. 병합 도구에서 두 개의 매니페스트에 값이 다른 동일한 속성이 포함된 것을 발견하면 병합 충돌이 발생합니다.

표 1은 병합 도구에서 모든 속성을 동일한 요소로 결합하려고 할 때 발생할 수 있는 결과를 보여줍니다.

표 1. 속성 값의 기본 병합 동작

우선순위가 높은 속성 우선순위가 낮은 속성 속성의 병합된 결과
값 없음 값 없음 값 없음(기본값 사용)
값 B 값 B
값 A 값 없음 값 A
값 A 값 A
값 B 충돌 오류 - 병합 규칙 마커를 추가해야 합니다.

그러나 병합 충돌을 피하기 위해 병합 도구가 다르게 동작하는 상황도 있습니다.

  • <manifest> 요소의 속성은 함께 병합되지 않습니다. 우선순위가 가장 높은 매니페스트의 속성만 사용됩니다.
  • <uses-feature> <uses-library> 요소의 android:required 속성은 OR 병합을 사용합니다. 충돌이 있는 경우 "true"이 적용되고 하나의 매니페스트에 필요한 기능 또는 라이브러리가 항상 포함됩니다.
  • <uses-sdk> 요소의 속성은 다음과 같은 상황을 제외하고 항상 우선순위가 높은 매니페스트의 값을 사용합니다.
    • 우선순위가 낮은 매니페스트에 더 높은 minSdk 값이 있다면 overrideLibrary 병합 규칙을 적용하지 않는 한 오류가 발생합니다.
    • 우선순위가 낮은 매니페스트에 더 낮은 targetSdkVersion 값이 있으면 병합 도구는 우선순위가 높은 매니페스트의 값을 사용하며, 가져온 라이브러리가 계속 제대로 작동하는지 확인하는 데 필요한 모든 시스템 권한도 추가합니다(예: 더 높은 버전의 Android에서 권한 제한이 증가한 경우). 이 동작에 관한 자세한 내용은 암시적 시스템 권한 관련 섹션을 참고하세요.
  • <intent-filter> 요소는 매니페스트 간에 일치하지 않습니다. 각각 고유하게 취급되며 병합된 매니페스트의 공통 상위 요소에 추가됩니다.

속성 간에 발생하는 다른 모든 충돌은 오류를 수신하며 우선순위가 높은 매니페스트 파일에 특수 속성을 추가하여 병합 도구에 오류를 해결할 방법을 지시해야 합니다. 병합 규칙 마커에 관한 다음 섹션을 참고하세요.

속성 기본값을 사용하지 마세요. 모든 고유한 속성은 동일한 요소로 결합되므로 우선순위가 높은 매니페스트가 속성의 기본값을 선언하지 않고 실제로 사용하면 예상치 못한 결과가 발생할 수 있습니다. 예를 들어, 우선순위가 높은 매니페스트가 android:launchMode 속성을 선언하지 않으면 기본값 "standard"를 사용합니다. 그러나 우선순위가 낮은 매니페스트가 이 속성을 다른 값으로 선언하면 병합된 매니페스트에는 이 값이 적용되고 그로 인해 기본값이 재정의됩니다. 각 속성에 원하는 값을 명시적으로 정의해야 합니다. 각 속성의 기본값은 매니페스트 참조에 설명되어 있습니다.

병합 규칙 마커

병합 규칙 마커는 병합 충돌 해결 방법에 관한 기본 설정을 표현하거나 원하지 않는 요소와 속성을 삭제하는 데 사용할 수 있는 XML 속성입니다. 전체 요소에 마커를 적용하거나 요소의 특정 속성에만 마커를 적용할 수 있습니다.

두 개의 매니페스트 파일을 병합할 때, 병합 도구는 우선순위가 높은 매니페스트 파일에서 이러한 마커를 찾습니다.

모든 마커는 Android tools 네임스페이스에 속하므로 다음과 같이 <manifest> 요소에서 이 네임스페이스를 먼저 선언해야 합니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    xmlns:tools="http://schemas.android.com/tools">

노드 마커

전체 XML 요소(지정된 매니페스트 요소의 모든 속성 및 모든 하위 태그)에 병합 규칙을 적용하려면 다음 속성을 사용합니다.

tools:node="merge"
병합 충돌 휴리스틱을 사용하는 충돌이 없으면 이 태그의 모든 속성과 모든 중첩된 요소를 병합합니다. 이것은 요소의 기본 동작입니다.

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge">
</activity>

병합된 매니페스트 결과:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
tools:node="merge-only-attributes"
이 태그의 속성만 병합합니다. 중첩된 요소를 병합하지 않습니다

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge-only-attributes">
</activity>

병합된 매니페스트 결과:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
</activity>
tools:node="remove"
병합된 매니페스트에서 이 요소를 제거합니다. 병합된 매니페스트에서 필요하지 않은 요소를 발견하고 이 요소가 제어할 수 없는 우선순위가 낮은 매니페스트 파일에서 제공한 것(예: 가져온 라이브러리)인 경우에 사용됩니다.

우선순위가 낮은 매니페스트:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

우선순위가 높은 매니페스트:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      tools:node="remove"/>
</activity-alias>

병합된 매니페스트 결과:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>
tools:node="removeAll"
tools:node="remove"와 비슷하지만, 동일한 상위 요소 내에서 이 요소 유형과 일치하는 모든 요소를 삭제합니다.

우선순위가 낮은 매니페스트:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

우선순위가 높은 매니페스트:

<activity-alias android:name="com.example.alias">
  <meta-data tools:node="removeAll"/>
</activity-alias>

병합된 매니페스트 결과:

<activity-alias android:name="com.example.alias">
</activity-alias>
tools:node="replace"
우선순위가 낮은 요소를 완전히 대체합니다. 즉, 우선순위가 낮은 매니페스트에 일치하는 요소가 있으면 이를 무시하고 이 매니페스트에 나타난 것과 똑같이 이 요소를 사용합니다.

우선순위가 낮은 매니페스트:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

우선순위가 높은 매니페스트:

<activity-alias android:name="com.example.alias"
    tools:node="replace">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>

병합된 매니페스트 결과:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>
tools:node="strict"
우선순위가 낮은 매니페스트의 이 요소가 우선순위가 높은 매니페스트의 요소와 정확히 일치하지 않을 때마다 빌드 실패가 발생합니다(다른 병합 규칙 마커에서 해결하지 않은 경우). 이는 병합 충돌 휴리스틱을 재정의합니다. 예를 들어, 우선순위가 낮은 매니페스트에 추가 속성을 포함하면 빌드가 실패합니다(반면, 기본 동작에서는 병합된 매니페스트에 추가 속성을 추가함).

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="strict">
</activity>

매니페스트 병합 오류가 발생합니다. strict 모드에서는 두 개의 매니페스트 요소가 다를 수 없습니다. 다른 병합 규칙 마커를 적용하여 이 차이를 해결해야 합니다. tools:node="strict"가 없으면 이 두 파일은 tools:node="merge"의 예와 같이 오류 없이 병합할 수 있습니다.

속성 마커

매니페스트 태그의 특정 속성에만 병합 규칙을 적용하려면 다음 속성을 사용합니다. 각 속성은 쉼표로 구분된 하나 이상의 속성 이름(속성 네임스페이스 포함)을 허용합니다.

tools:remove="attr, ..."
병합된 매니페스트에서 지정된 속성을 제거합니다. 우선순위가 낮은 매니페스트 파일에 이러한 속성이 포함되어 있고 이러한 속성을 병합된 매니페스트에는 포함하지 않으려는 경우에 사용됩니다.

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:remove="android:windowSoftInputMode">

병합된 매니페스트 결과:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">
tools:replace="attr, ..."
우선순위가 낮은 매니페스트에서 지정된 속성을 이 매니페스트의 속성으로 바꿉니다. 즉, 항상 우선순위가 높은 매니페스트 값을 유지합니다.

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:windowSoftInputMode="stateUnchanged">

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported">

병합된 매니페스트 결과:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
tools:strict="attr, ..."
우선순위가 낮은 매니페스트의 이러한 속성이 우선순위가 높은 매니페스트의 속성과 정확히 일치하지 않을 때마다 빌드 실패가 발생합니다. 이는 모든 속성의 기본 동작입니다. 단, 병합 충돌 휴리스틱에서 설명한 특수 동작이 있는 속성은 예외입니다.

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="landscape">
</activity>

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:strict="android:screenOrientation">
</activity>

매니페스트 병합 오류가 발생합니다. 다른 병합 규칙 마커를 적용하여 충돌을 해결해야 합니다. 이는 기본 동작이므로 tools:strict="screenOrientation"을 명시적으로 추가해도 동일한 결과가 발생합니다.

다음 예에서와 같이 하나의 요소에 여러 개의 마커를 적용할 수도 있습니다.

우선순위가 낮은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:allowTaskReparenting="true"
    android:windowSoftInputMode="stateUnchanged">

우선순위가 높은 매니페스트:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported"
    tools:remove="android:windowSoftInputMode">

병합된 매니페스트 결과:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:allowTaskReparenting="true"
    android:screenOrientation="portrait">

마커 선택기

가져온 라이브러리 중에서 특정 라이브러리에만 병합 규칙 마커를 적용하려면 라이브러리 패키지 이름으로 tools:selector 속성을 추가합니다.

예를 들어, 다음 매니페스트의 경우 remove 병합 규칙은 우선순위가 낮은 매니페스트 파일이 com.example.lib1 라이브러리에 속한 경우에만 적용됩니다.

<permission android:name="permissionOne"
    tools:node="remove"
    tools:selector="com.example.lib1">

우선순위가 낮은 매니페스트가 다른 소스에 포함된 것이라면 remove 병합 규칙은 무시됩니다.

참고: 속성 마커와 함께 병합 규칙을 사용하면 마커에서 지정한 모든 속성에 병합 규칙이 적용됩니다.

가져온 라이브러리에서 <uses-sdk> 재정의

기본적으로 minSdk 값이 기본 매니페스트 파일보다 큰 라이브러리를 가져오면 오류가 발생하여 라이브러리를 가져올 수 없습니다.

병합 도구가 이 충돌을 무시하고 앱의 낮은 minSdk 값을 유지하면서 라이브러리를 가져오려면 overrideLibrary 속성을 <uses-sdk> 태그에 추가합니다. 속성 값은 하나 이상의 라이브러리 패키지 이름(쉼표로 구분)일 수 있으므로 기본 매니페스트의 minSdk을 재정의할 수 있는 라이브러리를 표시합니다.

예를 들어, 앱의 기본 매니페스트가 다음과 같이 overrideLibrary를 적용합니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app"
          xmlns:tools="http://schemas.android.com/tools">
  <uses-sdk tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
...

그러면 다음 매니페스트가 <uses-sdk> 태그와 관련된 오류 없이 병합될 수 있으며 병합된 매니페스트는 앱 매니페스트에서 minSdk="2"를 유지합니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.lib1">
   <uses-sdk android:minSdk="4" />
...

암시적 시스템 권한

앱에서 자유롭게 액세스할 수 있었던 일부 Android API는 최신 버전의 Android에서 시스템 권한으로 제한되었습니다.

이러한 API 액세스가 예상되는 앱의 작동이 중단되지 않도록 최신 버전의 Android에서는 앱에서 targetSdkVersion을 버전 제한이 추가된 버전보다 낮은 값으로 설정하면 권한 없이 이러한 API에 계속 액세스하는 것을 허용합니다. 이 동작은 API에 액세스할 수 있는 암시적 권한을 앱에 효과적으로 부여합니다. targetSdkVersion의 값이 다른 병합된 매니페스트가 영향을 받을 수 있습니다.

우선순위가 낮은 매니페스트 파일에 암시적 권한을 제공하는 targetSdkVersion의 값이 낮고 우선순위가 높은 매니페스트에 동일한 암시적 권한이 없는 경우(targetSdkVersion이 제한이 추가된 버전 이상이므로) 병합 도구는 병합된 매니페스트에 명시적으로 시스템 권한을 추가합니다.

예를 들어, 앱에서 targetSdkVersion을 4 이상으로 설정하고 targetSdkVersion이 3 이하로 설정된 라이브러리를 가져오면 병합 도구는 병합된 매니페스트에 WRITE_EXTERNAL_STORAGE 권한을 추가합니다.

표 2에는 병합된 매니페스트에 추가할 수 있는 모든 권한이 나열되어 있습니다.

표 2. 병합 도구가 병합된 매니페스트에 추가할 수 있는 권한 목록

우선순위가 낮은 매니페스트의 선언 병합된 manifest에 추가되는 권한
targetSdkVersion은 3 이하임 READ_PHONE_STATE WRITE_EXTERNAL_STORAGE
targetSdkVersion은 15 이하이고 READ_CONTACTS를 사용함 READ_CALL_LOG
targetSdkVersion은 15 이하이고 WRITE_CONTACTS를 사용함 WRITE_CALL_LOG

병합된 매니페스트 검사 및 충돌 찾기

앱을 빌드하기 전이라도 병합된 매니페스트의 모습을 미리 볼 수 있습니다. 미리보기를 보려면 다음 단계를 따르세요.

  1. Android 스튜디오에서 AndroidManifest.xml 파일을 엽니다.
  2. 편집기의 하단에서 병합된 매니페스트 탭을 클릭합니다.

그림 2와 같이 병합된 매니페스트 뷰는 왼쪽에 병합된 매니페스트 결과를 표시하고 오른쪽에는 병합된 매니페스트 파일 각각의 관련 정보를 표시합니다.

우선순위가 낮은 매니페스트 파일에서 병합된 요소는 왼쪽에 다른 색상으로 강조표시됩니다. 각 색상의 키는 Manifest Sources에서 지정됩니다.

그림 2. 병합된 매니페스트 뷰.

빌드의 일부이지만 요소 또는 속성에 영향을 미치지 않은 매니페스트 파일은 Other Manifest Files에 나열됩니다.

요소의 원래 위치에 관한 정보를 확인하려면 왼쪽 창에서 요소를 클릭합니다. Merging Log에 세부정보가 표시됩니다.

충돌이 발생하면 Merging Errors 아래에 표시되며, 병합 규칙 마커를 사용하여 충돌을 해결하는 방법에 관한 권장사항도 함께 표시됩니다.

Event Log 창에도 오류가 표시됩니다. 오류를 보려면 View > Tool Windows > Event Log를 선택합니다.

병합 결정 트리의 전체 로그를 확인하려면 모듈의 build/outputs/logs/ 디렉터리에서 manifest-merger-buildVariant-report.txt라는 로그 파일을 참고하세요.

병합 정책

매니페스트 병합 도구는 하나의 매니페스트 파일의 모든 XML 요소를 다른 파일의 상응하는 요소와 논리적으로 연결할 수 있습니다. 병합기는 매칭 키를 사용하여 각 요소를 매칭합니다. 고유한 특성 값(예: android:name) 또는 태그 자체의 자연적인 고유성(예: <supports-screen> 요소는 하나만 존재 가능)을 이용합니다.

두 개의 매니페스트에 동일한 XML 요소가 있는 경우 도구에서 세 개의 병합 정책 중 하나를 사용하여 두 요소를 병합합니다.

병합
충돌하지 않는 모든 속성을 동일한 태그로 결합하고 각각의 병합 정책에 따라 하위 요소를 병합합니다. 서로 충돌하는 속성이 있으면 병합 규칙 마커로 병합합니다.
하위 요소만 병합
속성을 결합하거나 병합하지 않고 (우선순위가 가장 높은 매니페스트 파일이 제공한 속성만 유지) 병합 정책에 따라 하위 요소를 병합합니다.
Keep
요소는 '그대로' 두고 병합된 파일의 공통 상위 요소에 요소를 추가합니다. 같은 요소에 여러 개의 선언이 존재할 수 있을 때만 사용합니다.

표 3은 각 요소 유형, 사용한 병합 정책 유형, 두 매니페스트에서 요소 매칭을 판별하는 데 사용되는 키를 보여줍니다.

표 3. 매니페스트 요소 병합 정책 및 매칭 키

요소 병합 정책 매칭 키
<action> 병합 android:name 속성
<activity> 병합 android:name 속성
<application> 병합 <manifest>당 하나만 있음.
<category> 병합 android:name 속성
<data> 병합 <intent-filter>당 하나만 있음.
<grant-uri-permission> 병합 <provider>당 하나만 있음.
<instrumentation> 병합 android:name 속성
<intent-filter> Keep 매칭 없음. 상위 요소 내에서 여러 선언이 허용됨.
<manifest> 하위 요소만 병합 파일당 하나만 있음.
<meta-data> 병합 android:name 속성
<path-permission> 병합 <provider>당 하나만 있음.
<permission-group> 병합 android:name 속성
<permission> 병합 android:name 속성
<permission-tree> 병합 android:name 속성
<provider> 병합 android:name 속성
<receiver> 병합 android:name 속성
<screen> 병합 android:screenSize 속성
<service> 병합 android:name 속성
<supports-gl-texture> 병합 android:name 속성
<supports-screen> 병합 <manifest>당 하나만 있음.
<uses-configuration> 병합 <manifest>당 하나만 있음.
<uses-feature> 병합 android:name 속성 (존재하지 않으면 android:glEsVersion 속성)
<uses-library> 병합 android:name 속성
<uses-permission> 병합 android:name 속성
<uses-sdk> 병합 <manifest>당 하나만 있음.
맞춤 요소 병합 매칭 없음. 이는 병합 도구에 알려지지 않았으며 항상 병합된 매니페스트에 포함됩니다.

매니페스트에 빌드 변수 삽입

build.gradle 파일에 정의된 AndroidManifest.xml 파일로 변수를 삽입해야 한다면 manifestPlaceholders 속성을 사용하면 됩니다. 이 속성은 아래와 같이 키-값 쌍의 맵을 사용합니다.

Groovy

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
    }
    ...
}

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
    }
    ...
}

그런 다음 자리표시자 중 하나를 속성값으로 매니페스트 파일에 삽입할 수 있습니다.

<intent-filter ... >
    <data android:scheme="https" android:host="${hostName}" ... />
    ...
</intent-filter>

기본적으로 빌드 도구는 ${applicationId} 자리표시자에 앱의 애플리케이션 ID도 제공합니다. 이 값은 빌드 변형에 따른 변경사항을 포함해 항상 현재 빌드의 최종 애플리케이션 ID와 일치합니다. 빌드 변형 사이에서도 인텐트 작업과 같이 식별자에 고유한 네임스페이스를 사용하려고 할 때 유용합니다.

예를 들어 build.gradle 파일은 다음과 같습니다.

Groovy

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    flavorDimensions "type"
    productFlavors {
        free {
            applicationIdSuffix ".free"
            dimension "type"
        }
        pro {
            applicationIdSuffix ".pro"
            dimension "type"
        }
    }
}

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    flavorDimensions += "type"
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
            dimension = "type"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
            dimension = "type"
        }
    }
}

매니페스트에 애플리케이션 ID를 다음과 같이 삽입할 수 있습니다.

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>

'free' 제품 버전을 빌드하는 경우 매니페스트는 다음과 같습니다.

<intent-filter ... >
   <action android:name="com.example.myapp.free.TRANSMOGRIFY" />
    ...
</intent-filter>

자세한 내용은 애플리케이션 ID 설정을 참고하세요.