有关项目依赖包发生 Manifest Merge 冲突的详细解决方案
安卓开发使用 Gradle 插件管理依赖包确实非常方便,尤其是在解决一些依赖冲突的问题上。比如,重复依赖的问题,具体内容请我之前写的一篇文章:
开发中,你可能还会遇到一种情况,就是项目所引用的 AAR 、Library 等第三方库所包含的 Manifest 清单文件与主 Module (默认名为 app )中定义的 Manifest 内容合并时发生冲突。
举个例子。比如在项目中引用的某个 Library 的 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 控制台查看错误日志和对应的解决方案:


如上图所示,Library 与 主 Module 在合并 Manifest 时发生错误。其中还包含看到具体错误信息,注明了是 android:theme 属性发生冲突。并且给出了建议的解决方案,使用 tools:replace 方式解决冲突。
我们就按照错误提示在主 Module 的 Manifest 文件中添加这行设置试试看:(注意需要声明 tools 命名空间)
<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 合并相关的知识,在开发者官网上介绍得非常清楚,大家可以访问如下链接:
你以为这样就结束了吗,非也,还有一种极端情况。像上面这种情况,如果我们脑洞再开大一点,假设这个 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
如我们所想,合并时发生冲突。然而,痛苦的是这种情况下,编译器也无解,无法给出相应解决方案!


当然,这种情况很极端,但也不是没有出现的可能。第三方库和我们的 App Module 都想使用自己的属性,也在情理之中。那么怎么办呢,如果是本地 Library 依赖方式的话,还可以手动修改 Library 的 Manifest 内容。但是如果是远程依赖的 AAR的话,我们是改不了的啊。
这个时候,我们就得想办法在合并的时候自动删除 Library 的 Manifest 内容。伟大的 GitHub网站有一个插件,能够帮助我们实现这个功能。先上地址:
这个插件可以帮助我们做到这些:
- 删除 Application 节点中的指定属性;
- 删除 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 规则冲突的情况并不多见,而更多的是,普通属性的使用冲突。不过,还是值得注意一下,以备不时之需。
关于我:亦枫,博客地址:http://yifeng.studio/,新浪微博:IT亦枫
微信扫描二维码,欢迎关注我的个人公众号:安卓笔记侠
不仅分享我的原创技术文章,还有程序员的职场遐想
有关项目依赖包发生 Manifest Merge 冲突的详细解决方案的更多相关文章
- maven项目依赖包问题
问题 maven传递依赖 解决方案 前段时间,开发中遇到一个关于maven依赖包的问题:由于业务需要,支付网关对账代码中的slf4j-api包需要更新,原包为1.5.8版本,需要更新到1.6.4版 ...
- python批量导出项目依赖包及批量安装的方法
在Python中我们在项目中会用到各种库,自带的自然不必再说,然而如果是三方库,则在进行项目移植时通常需要在新的环境下安装需要的三方库文件,面对较大项目中众多的三方库,可以先将项目依赖库导出到txt文 ...
- 一gradle创建SSM项目——依赖包
build.gradle compile:编译时必须. runtime:运行时必须,包括编译时. testCompile:测试编译时必须. testRuntime:测试运行时必须,包括编译时. 注:此 ...
- pip导出项目依赖包名称及版本,再安装命令
A导出依赖 pip freeze >requirements.txt B导入安装依赖 pip install -r requirements.txt 使用下面的命令安装依赖能自动跳过安装错误的依 ...
- android studio学习----添加项目依赖包补充---添加github上的开源项目为库
导入maven中的库 如果开源库作者有将代码放到Maven库中,我们可以在gradle配置中直接引入,类似如下: compile 'com.github.dmytrodanylyk.android-p ...
- android studio学习----添加项目依赖包总结
Gradle Library Projects Gradle 项目可以依赖于其它组件.这些组件可以是外部二进制包,或者是其它的 Gradle 项目. 在本例中, app/build.gradle 中有 ...
- python 只导出项目依赖包
平时导出依赖一般都是 pip freeze > requirements.txt 这种方式导出的是当前python环境中所有的包,只会多不会少,有些库不是必需的也跟着导出来,冗余过重. 这 ...
- nuget在jenkins上不能自动还原项目依赖包---笔记
最近遇到一个情况,IDE 是 VS2015 Update3 ,新建一个library项目(暂时叫做 mytests),然后用 nuget 安装了一个 Shouldly 包 在 VS 上一切正常,可以跑 ...
- Idea 2018.2.5创建springboot项目依赖包没有的错误
随机推荐
- [Linux 006]——grep和正则表达式
在使用系统时,我们或多或少的有一些搜索.查找的需求,必须要在文本中搜索某个关键字,或者过滤出文本中某些特定的行.grep 命令就为我们提供了这样一个功能,同时,grep 还可以使用正则表达式进行匹配, ...
- git的应用
对git的应用 (终于第一次用会git) 根据胡东晖同学的博客(使用git推送代码到开源中国以及IDEA环境下使用git)与热心指导,自己跟着做了,虽然途中出了很多很多问题,但是好在最后还是成功了!! ...
- 20145329吉东云 《Java程序设计》 第一周学习总结
一.JAVA平台概述 1.Java诞生于1995年5月23日,java体系架构分为JavaSE.JavaME.JavaEE三大平台,本章重点介绍了JavaSE.JavaSE分为四个主要部分:JVM.J ...
- 试编hello world
这里是一些vim的使用方法: 这时不知道怎么编译了 看了上面的知识 也问了志伟,我就知道了.是要“./hello”就可以了 自己敲了代码,今后也会多试运行,编译,得尽快安装虚拟机了.
- MR案例:Reduce-Join
问题描述:两种类型输入文件:address(地址)和company(公司)进行一对多的关联查询,得到地址名(例如:Beijing)与公司名(例如:Beijing JD.Beijing Red Star ...
- hadoop 编译任意版本的eclipse 插件
github地址 下载ant并进行配置 http://ant.apache.org/bindownload.cgi 解压后, sudo gedit /etc/profile 进行设置: 添加expor ...
- Elasticsearch 使用技巧笔记
1.重新分片 当出现Unassigned分片时,我们可以通过分片重分配解决这个问题 curl -X PUT http://192.168.0.37:9200/_cluster/settings \ - ...
- HtmlAgilityPach基本使用方法
//过滤html标签 static void InnerText() { HtmlWeb htmlWeb = new HtmlWeb(); HtmlDocument doc = htmlWeb.Loa ...
- android AVD启动失败原因之一
在mac上安装好Android SDK.AVD及相关的组件之后,手动创建了一个安卓模拟器后,通过actions启动,会弹出一个提示窗口,然后就闪退,也没有报错什么的,在网上搜了半天AVD启动失败的问题 ...
- http & https & http2.0
一.http状态码 1xx(信息性状态码,接受的请求正在处理) 2xx(成功状态码,请求正常处理完毕)200 OK204 No Content:请求成功但没有资源返回206 Partial Conte ...
