加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

有关项目依赖包发生 Manifest Merge 冲突的详细解决方案

发布时间:2020-12-14 01:04:36 所属栏目:百科 来源:网络整理
导读:安卓开发使用 Gradle 插件管理依赖包确实非常方便,尤其是在解决一些依赖冲突的问题上。比如,重复依赖的问题,具体内容请我之前写的一篇文章: 有关 Android Studio 重复引入包的问题和解决方案 开发中,你可能还会遇到一种情况,就是项目所引用的 AAR 、Li

安卓开发使用 Gradle 插件管理依赖包确实非常方便,尤其是在解决一些依赖冲突的问题上。比如,重复依赖的问题,具体内容请我之前写的一篇文章:

  • 有关 Android Studio 重复引入包的问题和解决方案

开发中,你可能还会遇到一种情况,就是项目所引用的 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
  • 1
  • 2

通过点击 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">
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

    • Merge Multiple Manifest Files

    你以为这样就结束了吗,非也,还有一种极端情况。像上面这种情况,如果我们脑洞再开大一点,假设这个 Library 也使用了tools:replace属性会发生什么情况呢。我们不妨试验一下。修改 Library 的 Manifest 内容:

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

    而此时 app module 中的 Manifest 内容的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
        2

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

    • 当然,这种情况很极端,但也不是没有出现的可能。第三方库和我们的 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'
        }
    }
      2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后在 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
            }
        }
          8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38

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

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

        android.buildCacheDir=./build-cache
          1

        这些工作都做完之后,我们再次 Build 工程,就能成功编译通过啦。

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



      转自:http://blog.csdn.net/growing_tree/article/details/74938536

      (编辑:李大同)

      【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读