The foreword 0.

AndroidStuido adopts a modular construction approach, with each module configured with an Androidmanifest.xml, and even each build type and product feature can be configured with an Androidmanifest.xml. When the APK is finally generated, it is merged according to the priority specified in the following figure. (Image credit: Official Google docs)

1. Priority definition

The figure above shows the merge process of three manifest files, from left to right, with the lowest priority.

1.1 Build a variation manifest file

Build a list of variants, including two main ones: buildType and productFlavor.

The priorities in descending order are:

  1. ProductFlavors.
  2. BuildType.
  3. Compile variants (a combination of the first two).
    buildTypes {
        // Test the version
        debug {
        }
        // Release
        release {
        }
    }

    flavorDimensions 'stage'.'api'

    productFlavors {
        // Development phase
        dev {
            dimension 'stage'
        }
        // Production phase
        pro {
            dimension 'stage'
        }

        minApi21 {
            dimension 'api'
        }
        minApi23 {
            dimension 'api'
        }
        minApi26 {
            dimension 'api'}}Copy the code

Build the corresponding compilation variant directory and androidmanifest.xml file respectively.

For example, the preceding configurations have priorities in descending order:

dev -> minApi23 -> devMinApi23 -> debug -> devMinApi23Debug

  • Dev is higher than minApi23 because flavorDimensions declares the stage prior to the API.
  • There is no combination of devDebug and minApi23Debug.

1.2 Apply the main module manifest file

The manifest file in the main module, the androidmanifest.xml file in the main directory.

1.3 Library module and dependent library list file

Dependent libraries refer to aar files that depend on local or remote Maven repositories. They usually contain an androidmanifest.xml file.

Tripartite libraries of type JAR, only class files, are beyond the scope of this discussion.

In contrast to the main module, a library module can also contain multiple build types and product features. First, they merge an Androidmanifest.xml file of their own according to the priority defined by the build variant manifest file, which is then merged as a library module manifest file with the main module manifest file.

2. Implicit system permissions

The apis that were freely accessible to applications in earlier versions of Android are limited by system permissions in the new version. To accommodate these applications, the new version will allow them to access these restricted apis without permission.

For example, WRITE_EXTERNAL_STORAGE first appears in Android API 4. Then, when your application’s targetSdkVersion is set to less than 4, you can also access external storage without permission.

In the AndroidManifest merge, these implicit permissions are automatically added to the merged AndroidManifest if the targetSdkVersion in the low-priority Manifest is less than 4.

The following two pictures before and after the merger, app/AndrodManifest. XML and library/AndroidManifest. Comparison of XML.

No permissions are declared in app/ androdmanifest.xml before the merge, but three permissions are added after the merge.

A lower-priority list declaration Permissions added to the merged manifest
targetSdkVersion <= 3 WRITE_EXTERNAL_STORAGE

READ_EXTERNAL_STORAGE

READ_PHONE_STATE
targetSdkVersion <= 15

And use READ_CONTACTS
READ_CALL_LOG
targetSdkVersion <= 15

And use WRITE_CONTACTS
WRITE_CALL_LOG

Implicit system permissions are mainly compatible with earlier versions of Android. Not much in 9102 and later development. Therefore, understand.

3. Merge rules

Borrow an official chart, introduced in the merge process, some default merge methods.

For example, dev has a high priority and debug has a low priority:

<! - dev Manifest - >
<activity
    android:name="com.flueky.lib.TestActivity"
    android:exported="false"
    android:windowSoftInputMode="adjustPan">
    <meta-data
        android:name="dev_index"
        android:value="dev" />
</activity>
<! - the debug Manifest - >
<activity android:name="com.flueky.lib.TestActivity"
    android:exported="false"
    android:screenOrientation="portrait">
    <meta-data
        android:name="debug_index"
        android:value="debug" />
</activity>   
Copy the code
  1. Dev has no value, the debug value B, the combined value B, android: screenOrientation = “portrait”.
  2. A dev values, the debug no value, the combined value A, android: windowSoftInputMode = “adjustPan”.
  3. Dev value A, debug value A, merged value A, Android: Exported =”false”.

Therefore, the final merge result is as follows:

<! DevDebug Manifest-->
<activity android:name="com.flueky.lib.TestActivity"
    android:screenOrientation="portrait"
    android:exported="false"
    android:windowSoftInputMode="adjustPan">
    <meta-data
        android:name="dev_index"
        android:value="dev" />
    <meta-data
        android:name="debug_index"
        android:value="debug" />
</activity>  
Copy the code

All the attributes mentioned above were merged, but the meta-data tag was eventually merged as well. Tag merging, everyone is familiar with Activity merging. Each module’s Activity only needs to be registered in that module’s AndroidManifst.xml. It does not need to be registered again in the main module because they will eventually be merged together.

Tag merging uses a matching key as the basis, the activity uses Android: Name as the match, and so does meta-data. If the attribute values of the matching keys are different, the matching keys can be merged without conflict.

The following table lists all the match keys of the manifest subtags for reference to resolve merge conflicts.

The label Merge strategy Match keys
action merge The android: name attribute
activity merge The android: name attribute
application merge There is only one manifest
category merge The android: name attribute
data merge There is only one intent-filter per intent
grant-uri-permission merge There is only one provider per provider
instrumentation merge The android: name attribute
intent-filter keep Don’t match; Allow multiple declarations within the parent element
manifest Only child elements are merged There is only one file per file
meta-data merge The android: name attribute
path-permission merge There is only one provider per provider
permission-group merge The android: name attribute
permission merge The android: name attribute
permission-tree merge The android: name attribute
provider merge The android: name attribute
receiver merge The android: name attribute
screen merge Android: screenSize properties
service merge The android: name attribute
supports-gl-texture merge The android: name attribute
supports-screen merge There is only one manifest
uses-configuration merge There is only one manifest
uses-feature merge The android: name attribute

(If not, use the Android :glEsVersion attribute.)
uses-library merge The android: name attribute
uses-permission merge The android: name attribute
uses-sdk merge There is only one manifest
Custom elements merge Don’t match; The merge tool is not aware of these elements,

So they are always included in the merged listing

In Android, conflicts are resolved during the merge process by means of tags. Attribute tags and node tags (tags as nodes) are used to resolve conflicts artificially in accordance with attribute and tag merging described earlier.

You need to use the Android Tools namespace.

xmlns:tools="http://schemas.android.com/tools"
Copy the code

4. Attribute tags

There are four attribute tags. Default tag, remove, replace, selector.

tag role
tools:strict The default flag is meaningless. Use replace and remove to resolve conflicts
tools:replace Specifies the name of the property to replace
tools:remove Specifies the name of the property to remove
tools:selector Select the specified module to merge with replace and remove

These examples are relatively simple, borrow the official sample code.

  1. Replace Example.
<! -- Low priority -->
<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:windowSoftInputMode="stateUnchanged">
<! -- High priority -->    
<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported">
<! -- After merger -->    
<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">            
Copy the code
  1. Remove Example.
<! -- Low priority -->
<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
<! -- High priority -->
<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:remove="android:windowSoftInputMode">
<! -- After merger -->    
<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">            
Copy the code
  1. Selector indicates that only low-priority Androidmanifest.xml from a specified source is merged.
<! -- low priority from com.example.lib1 -->
<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
<! -- High priority -->
<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:remove="android:windowSoftInputMode"
    tools:selector="com.example.lib1">
<! -- After merger -->    
<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">            
Copy the code

5. Node tag

Use Tools :node to mark nodes.

Attribute values role
merge The default is to merge all attributes and all nested elements of a tag when no conflicts occur
merge-only-attributes Not validated correctly, it is estimated to be invalid.
remove Remove this label after merge
removeAll Similar to remove, but removes all of the tags
replace Replace the same label in lower priority
strict If any tag does not match, the merge fails. You need to use the preceding attribute values to resolve the problem


<! DevDebug Manifest-->
<activity android:name="com.flueky.lib.TestActivity"
    android:screenOrientation="portrait"
    android:exported="false"
    android:windowSoftInputMode="adjustPan">
    <meta-data
        android:name="dev_index"
        android:value="dev" />
    <meta-data
        android:name="debug_index"
        android:value="debug" />
</activity>  
Copy the code
  1. Merge-only -attributes did not find the correct use as described in the documentation.

  2. Use remove to remove labels that match the same key.

<! - low priority - > < activity android: name = "com. Flueky. Lib. TestActivity" android: exported = "false" android:screenOrientation="portrait"> <meta-data android:name="debug_index" android:value="debug" /> </activity> <! - high priority - > < activity < activity android: name = "com. Flueky. Lib. TestActivity" android: windowSoftInputMode = "adjustPan" > <meta-data android:name="debug_index" tools:node="remove" /> </activity> <! - combined - > < activity android: name = "com. Flueky. Lib. TestActivity" android: exported = "false" android:windowSoftInputMode="adjustPan" android:screenOrientation="portrait"> </activity>Copy the code
  1. With removeAll:
<! -- Low priority -->
<activity
    android:name="com.flueky.lib.TestActivity"
    android:exported="false"
    android:screenOrientation="portrait">
    <meta-data
        android:name="debug_index"
        android:value="debug" />
    <meta-data
        android:name="dev_index"
        android:value="dev" />    
</activity>
<! -- High priority -->
<activity
    android:name="com.flueky.lib.TestActivity"
    android:windowSoftInputMode="adjustPan">
    <meta-data
        tools:node="removeAll" />
</activity>
<! -- After merger -->
<activity
    android:name="com.flueky.lib.TestActivity"
    android:exported="false"
    android:windowSoftInputMode="adjustPan"
    android:screenOrientation="portrait">
</activity>    
Copy the code

RemoveAll Removes all the same tags.

  1. With replace, the result is straightforward.
<! -- Low priority -->
<activity
    android:name="com.flueky.lib.TestActivity"
    android:screenOrientation="portrait">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
<! -- High priority -->
<activity
    android:name="com.flueky.lib.TestActivity"
    android:windowSoftInputMode="adjustPan"
    tools:node="replace">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>   
<! -- After merger --> 
<activity
    android:name="com.flueky.lib.TestActivity"
    android:windowSoftInputMode="adjustPan">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>       
Copy the code

After using replace merge, the configuration in the higher priority is directly followed.

6. Frequently Asked Questions

The most common problem encountered when integrating third-party libraries is that the minimum SDK version of the library is smaller than the minimum SDK version of the project. Problems are bound to arise when integrating third-party libraries at this point.

Solutions:

<! -- com.flueky.library -- packageName -->
<uses-sdk tools:overrideLibrary="com.flueky.library" />
Copy the code

Finally, on the sly, AndroidStudio version 3.5.2 supports viewing the merged androidmanifest.xml file directly.

The source address

Think it works? I’ll give you a bonus.To play to admire

Flueky.github. IO /