Merging Multiple Manifest Files: Android

Md Munir Hossain
Oceanize Lab Geeks
4 min readDec 29, 2017

--

Your APK file can contain just one AndroidManifest.xml file, but your Android Studio project may contain several—provided by the main source set, build variants, and imported libraries. So when building your app, the Gradle build merges all manifest files into a single manifest file that's packaged into your APK.

Merge priorities

The merger tool combines all the manifest files into one file by merging them sequentally based on each manifest file’s priority. For example, if you have three manifest files, the lowest priority manifest is merged into the next highest priority, and then that is merged into the highest priority manifest.

Merge conflict heuristics

If an element from the lower-priority manifest does not match any elements in the higher-priority manifest, then it is added to the merged manifest. However, if there is a matching element, then the merger tool attempts to combine all attributes from each into the same element. If the tool finds that both manifests contain the same attribute with different values, then a merge conflict occurs.

However, there are a few situations in which the merger tool behaves differently to avoid merge conflicts:

  • Attributes in the <manifest> element are never merged together—only the attributes from the highest priority manifest are used.
  • The android:required attribute in the <uses-feature> and <uses-library> elements use an OR merge, such that if there is a conflict, "true"is applied and the feature or library required by one manifest is always included.
  • Attributes in the <uses-sdk> element always use the value from the higher-priority manifest, except in the following situations:
  • When the lower-priority manifest has a minSdkVersion value that's higher, an error occurs unless you apply the overrideLibrary merge rule.
  • When the lower-priority manifest has a targetSdkVersion value that's lower, the merger tool uses the value from the higher-priority manifest, but it also adds any system permissions that are necessary to ensures that the imported library continues to function properly (for cases in which the higher Android version has increased permission restrictions). For more information about this behavior, see the section about implicit system permissions.
  • The <intent-filter> element is never matched between manifests. Each is treated as unique and is added to the common parent element in the merged manifest.

Merge rule markers

A merge rule marker is an XML attribute you can use to express your preference about how to resolve merge conflicts or remove unwanted elements and attributes. You can apply a marker to either an entire element or to just specific attributes in an element.

When merging two manifest files, the merger tool looks for these markers in the higher-priority manifest file.

All markers belong to the Android tools namespace, so you must first declare this namespace in the <manifest> element as shown here:

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

Node markers

To apply a merge rule to an entire XML element (to all attributes in a given manifest element and to all its child tags), use the following attributes:

tools:node="merge"Merge all attributes in this tag and all nested elements when there are no conflicts using the merge conflict heuristics. This is the default behavior for elements.

Low priority manifest:

<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>

High priority manifest:

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

Merged manifest result:

<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>

Attribute markers

To instead apply a merge rule only to specific attributes in a manifest tag, use the following attributes. Each attribute accepts one or more attribute names (including the attribute namespace), separated by commas.

tools:remove="attr, ..."Remove the specified attributes from the merged manifest. Although it seems like you could instead just delete these attributes, it's necessary to use this when the lower-priority manifest file does include these attributes and you want to ensure they do not go into the merged manifest.

Low priority manifest:

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

High priority manifest:

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

Merged manifest result:

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

Marker selector

If you want to apply the merge rule markers to only a specific imported library, add the tools:selector attribute with the library package name.

For example, with the following manifest, the remove merge rule is applied only when the lower-priority manifest file is from the com.example.lib1library.

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

If the lower-priority manifest is from any other source, the remove merge rule is ignored.

Override <uses-sdk> for imported libraries

By default, when importing a library with a minSdkVersion value that's higher than the main manifest file, an error occurs and the library cannot be imported. To make the merger tool ignore this conflict and import the library while keeping your app's lower minSdkVersion value, add the overrideLibrary attribute to the <uses-sdk> tag. The attribute value can be one or more library package names (comma-separated), indicating the libraries that can override the main manifest's minSdkVersion.

For example, if your app’s main manifest applies overrideLibrary like this:

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

--

--