Using the Gradle plugin to manage dependencies is really handy for Android developers, especially when it comes to resolving dependency conflicts. For example, the problem of repeated dependence, the specific content of an article I wrote before:

  • Issues and solutions regarding the repeated introduction of packages in Android Studio

During development, you may also encounter situations where the Manifest file contained in the AAR, Library, and other third-party libraries referenced by the project conflicts with the Manifest content defined in the main Module (named app by default).

Let me give you an example. For example, in the AndroidManifest file of a Library referenced in the project, the application tag reads as follows:

<application 
    android:theme="@android:style/Theme.Black"/>Copy the code

The Android :theme attribute is also defined in the AndroidManifest file of our app Module main project:

<application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">Copy the code

And they use different values. A merge conflict occurs at compile time with the following error message:

Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed with multiple errors, see logsCopy the code

You can open the Gradle Console to view the error log and the corresponding solution by clicking the [Show Console Output] option on the left side of the Messages menu:

As shown above, Library and main Module failed to merge Manifest. It also contains a specific error message indicating that the Android :theme property has conflicted. It also gives a suggested solution to solve the conflict by using tools:replace.

Let’s try adding this line to the Manifest file of the main Module as prompted:

<application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:replace="android:theme">Copy the code

This way, the next Build will compile. Set Manifest’s merge priority with the Tools domain space. Tools :place: removes attributes from the low-priority Library and uses attributes defined in the higher-priority App Module.

Manifest merges are well covered on the developers’ website, and you can visit the following link:

  • Merge Multiple Manifest Files

You think that’s the end of it? No, there’s another extreme. In this case, imagine what would happen if the Library also used the Tools :replace attribute. We might as well try it out. Modify the Manifest content of Library:

<application 
    android:theme="@android:style/Theme.Black"
    tools:replace="android:theme"/>Copy the code

The tools:replace attribute in the Manifest content of the App Module has also been modified:

<application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:replace="android:allowBackup, android:theme">Copy the code

Here, I deliberately set the tools: Replace property to different values for both. Build and see the result:

Error:Execution failed for task ':app:processDebugManifest'.
> Multiple entries with same key: android:theme=REPLACE and android:theme=REPLACECopy the code

As we thought, there were conflicts at merge time. However, in this case, the compiler also has no solution to provide the corresponding solution!

This scenario is extreme, of course, but it’s not out of the question. It makes sense for third-party libraries and our App Module to want to use their own properties. If this is a local Library dependency, you can manually modify the Library Manifest content. But if it’s a remote AAR, we can’t change.

At this point, we need to find a way to automatically delete the Library Manifest content when merging. The great GitHub site has a plugin that helps us do this. Address:

  • github.com/2BAB/Seal

This plugin helps us do this:

  1. Delete the specified property from the Application node.
  2. Delete the Application nodetools:replaceProperty of the specified value.

Using the example above, we will introduce the use of the Seal plug-in.

Start by setting the address of the Seal plug-in in the build.gradle file at the root of the project:

Dependencies buildscript {repositories {jcenter ()} {the classpath 'com. Android. View the build: gradle: 2.3.0' classpath 'me. Xx2bab. Gradle: seal - the manifest - precheck - plugin: 1.0.0'}}Copy the code

Then reference the plugin in the build.gradle file of the app Module:

apply plugin: 'com.android.application'
apply plugin: 'seal'Copy the code

Next, modify the build.gradle file again and configure the deletion rule when merging:

def projectRoot = project.getRootProject().rootDir.absolutePath // Folders may include AndroidManifest.xml files // 1. For Gradle plugin 2.3.0 or higher, build-cache is default choice, // 2. But we should make sure snapshot-libs will be checked too. // 3. Free to add your folders for more customization def manifestPath = [ // for AAR of Release // see note below projectRoot + '/build-cache', projectRoot + '/samplelibrary', // for AAR of SNAPSHOT projectRoot + '/app/build/intermediates/exploded-aar' ] def removeAttrs = [ 'android:theme' ] def  replaceValues = [ 'android:theme' ] seal { enabled = true manifests = manifestPath appAttrs { enabled = true attrsShouldRemove = removeAttrs } appReplaceValues { enabled = true valuesShouldRemove = replaceValues } }Copy the code

Note that you add the conflicting Library name introduced by your project under the manifestPath configuration, using the Samplelibrary in the example. Add conflicting attribute names to removeAttrs and replaceValues. In this case, the android:theme attribute is used.

If build-cache is enabled for Gradle (by default from Gradle 2.3), you need to add the following content to the gradle.properties file in your project root directory:

android.buildCacheDir=./build-cacheCopy the code

After all this work is done, we will Build the project again and it will compile successfully.

Of course, it’s rare to see a tools rule conflict in a Manifest merge in a real project, rather than a common attribute use conflict. Still, it’s worth taking note, just in case.

About me: Yifeng, blog address: Yifeng. Studio /, Sina Weibo: IT Yifeng

Scan the QR code on wechat, welcome to follow my personal public account: Android Notexia

Not only share my original technical articles, but also the programmer’s workplace reverie