Android studio Module依赖 出现Manifest Merge 冲突的详细解决方案

安卓开发使用 Gradle 插件管理依赖包确实非常方便,开发中,你可能还会遇到一种情况,就是项目所引用的 AAR 、Library 等第三方库所包含的 Manifest 清单文件与主 Module (默认名为 app )中定义的 Manifest 内容合并时发生冲突。

比如在项目中引用的某个 Library 或者Module的 AndroidManifest 文件中,application 标签中内容如下:

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

其中的 android:theme 属性在我们的 app module 主工程的 AndroidManifest 文件中也被定义:

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

并且二者所使用的值不同。这样,在编译的时候就会发生合并冲突,错误信息如下:

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

通过点击 Messages 菜单左侧【Show Console Output】选项可以打开 Gradle Console 控制台查看错误日志和对应的解决方案:

Paste_Image.png
Paste_Image.png

如上图所示,Library 与 主 Module 在合并 Manifest 时发生错误。其中还包含看到具体错误信息,注明了是 android:theme 属性发生冲突。并且给出了建议的解决方案,使用 tools:replace 方式解决冲突。

我们就按照错误提示在主 Module 的 Manifest 文件中添加这行设置试试看:(注意需要声明 tools 命名空间)

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

并且在 app module 中的 Manifest 内容的 tools:replace 属性也做了一些修改

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

如此这样,再次 Build 时便能编译通过。其实原理就是,借助 tools 域名空间设置 Manifest 的合并优先级问题。这里 tools:place 表明合并时移除低优先级 Library 中的相关属性,使用高优先级 app module 中定义的对应属性内容。

有关 Manifest 合并相关的知识,在开发者官网上介绍得非常清楚,大家可以访问如下链接:

Merge Multiple Manifest Files

像上面这种情况,如果我们脑洞再开大一点,假设这个 Library 也使用了 tools:replace 属性会发生什么情况呢。我们不妨试验一下。修改 Library 的 Manifest 内容:

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

而此时 app module 中的 Manifest 内容的 tools:replace 属性也做了一些修改:

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

这里,我故意设置二者的 tools:replace 属性为不同值。Build 一下,看看结果:

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

如我们所想,合并时发生冲突。然而,痛苦的是这种情况下,编译器也无解,无法给出相应解决方案!

Paste_Image.png
Paste_Image.png

当然,这种情况很极端,但也不是没有出现的可能。第三方库和我们的 App Module 都想使用自己的属性,也在情理之中。那么怎么办呢,如果是本地 Library 依赖方式的话,还可以手动修改 Library 的 Manifest 内容。但是如果是远程依赖的 AAR的话,我们是改不了的啊。

这个时候,我们就得想办法在合并的时候自动删除 Library 的 Manifest 内容。但是很幸运 GitHub网站有一个插件,能够帮助我们实现这个功能。先上地址:
https://github.com/2BAB/Seal

这个插件可以帮助我们做到这些:

1、删除 Application 节点中的指定属性;
2、删除 Application 节点中 tools:replace 属性的指定值。
这里我们还用上面的例子,介绍一下 Seal 插件的使用方式。

首先在项目根目录下的 build.gradle 文件中设置 Seal 插件的地址:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0'
        classpath 'me.xx2bab.gradle:seal-manifest-precheck-plugin:1.0.0'
    }
}

然后在 app module 的 build.gradle 文件中引用这个插件:

apply plugin: 'com.android.application'
apply plugin: 'seal'

接着还是修改这个 build.gradle 文件,配置合并时的删除规则:

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

注意,在 manifestPath 配置下添加自己项目引入并发生冲突的 Library 名字,例子中使用的是 samplelibrary。同时在
removeAttrs 和 replaceValues 配置下添加对应冲突的属性名字,例子中冲突的是 android:theme 属性。

还有一点需要注意的是,如果 Gradle 插件开启了 build-cache 功能(Gradle 插件 2.3 版本开始默认开启),还需要在项目根目录下的 gradle.properties 文件中添加如下内容:

android.buildCacheDir=./build-cache

我们再次 Build 工程,就能成功编译通过啦。

当然,真实项目中 Manifest 合并时能遇到 tools 规则冲突的情况并不多见,而更多的是,普通属性的使用冲突。不过,还是值得注意一下,以备不时之需。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,818评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,778评论 6 342
  • Gradle是什么? Android Studio 基于 Gradle 构建系统,并通过 Android Grad...
    CP9阅读 1,230评论 0 3
  • 天气变幻总是很反常,忽冷忽热,让人无所适从。也就有了街上行人乱穿衣的各类镜头,有怕冷的还穿着棉袄和羽绒服,爱美的小...
    欢鱼儿阅读 268评论 2 2
  • 狂飙42天,朋友圈现象级产品分答是怎样做出的?
    方伟在学习阅读 267评论 0 0