如何正确地从Maven仓库中使用Gradle移除一个传递性依赖?

4

在构建我的项目时,出现了以下错误:

UNEXPECTED TOP-LEVEL EXCEPTION:
    com.android.dex.DexException: Multiple dex files define Lorg/slf4j/impl/StaticLoggerBinder;
        at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:594)
        at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:552)
        at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:533)
        at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:170)
        at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
        at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
        at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
        at com.android.dx.command.dexer.Main.run(Main.java:230)
        at com.android.dx.command.dexer.Main.main(Main.java:199)
        at com.android.dx.command.Main.main(Main.java:103)

我理解这是因为我有多个依赖于slf4j的库。在我的build.gradle文件中,依赖关系如下:

dependencies {
    compile project(':libraries:some-sdk')
    compile files('libs/some-library.jar')
    compile 'com.some-module:some-artifact:X.X.X'
    compile 'com.github.tony19:logback-android-classic:1.1.1-3'
}

我知道logback-android-classic依赖是问题所在,因为它确实依赖于slf4j,如果我将其注释掉,我的项目就可以正常构建。根据我找到的其他来源,通常通过排除传递依赖项来解决这个问题,像这样:

compile('com.github.tony19:logback-android-classic:1.1.1-3') {
    exclude group: 'org.slf4j'

然而,即使我清理并重新构建后,仍然出现错误。

更新: 按照dmahapatro的建议运行dependencyInsight查找slf4j没有返回结果:

$ gradle -q dependencyInsight --dependency slf4j --configuration compile
No dependencies matching given input were found in configuration ':main:compile'

我的完整依赖树如下:

+--- project :stripe
+--- project :apptentive-android-sdk
+--- project :numberpicker
+--- project :switch-backport
+--- org.jsoup:jsoup:1.7.3
+--- org.ocpsoft.prettytime:prettytime:3.2.4.Final
+--- org.mockito:mockito-all:1.9.5
+--- com.google.dexmaker:dexmaker:1.0
+--- com.google.dexmaker:dexmaker-mockito:1.0
+--- com.pusher:pusher-java-client:0.3.1
\--- com.github.tony19:logback-android-classic:1.1.1-3
     +--- com.github.tony19:apktool-lib:1.4.4-3
     |    \--- com.google.android:android:2.1_r1
     |         +--- commons-logging:commons-logging:1.1.1
     |         +--- org.apache.httpcomponents:httpclient:4.0.1
     |         |    +--- org.apache.httpcomponents:httpcore:4.0.1
     |         |    +--- commons-logging:commons-logging:1.1.1
     |         |    \--- commons-codec:commons-codec:1.3
     |         +--- org.khronos:opengl-api:gl1.1-android-2.1_r1
     |         +--- xerces:xmlParserAPIs:2.6.2
     |         \--- xpp3:xpp3:1.1.4c
     \--- com.github.tony19:logback-android-core:1.1.1-3

更新2:
我已经将冲突范围缩小到了logback-android-classic库和一个本地的jar包(不幸的是,由于许可问题,我无法直接编辑该jar包)。排除其中任何一个都可以解决冲突。只有这两个依赖项的空通用测试应用程序也将出现冲突。我已经验证了本地jar包中包含org.slf4j,但由于前面提到的许可证问题,我不能做太多事情。所以我的唯一选择就是从logback-android-classic中排除slf4j。考虑到依赖树实际上并没有显示slf4j作为logback-android-classic的依赖项,并且考虑到添加
    compile('com.github.tony19:logback-android-classic:1.1.1-3') {
            exclude group: 'org.slf4j'
    }

问题未得到解决,我该如何从logback-android-classic中排除slf4j依赖?

最终更新: 最终,通过与我使用的本地jar包所有者合作,成功将logback移除。我怀疑这对于未来的访问者来说并不是特别有用的答案,但为了完整起见,我还是想把它包括在内。


1
运行 dependencyInsight 命令以查看 slf4j 是从哪里被引入的。命令如下:gradle -p dependencyInsight --dependency slf4j --configuration compile。这将使事情变得清晰明了。 - dmahapatro
我遇到了“找不到名称为'compile'的配置”的问题。通常这是由于缺少build.gradle文件引起的,但我已经验证它们都存在。有什么提示吗?否则我想这可能是一个独立的问题。 - rhnoble
我已经意识到在那里使用“-p”没有意义。仍然出现“找不到名称为'compile'的配置”的错误。 - rhnoble
好的,我想我当时有点傻。我是在根项目上运行该命令,而不是我的主要项目上运行。当我在我的主要项目上运行它时,它确实找到了编译配置,但没有找到slf4j。"在配置':main:compile'中未找到与给定输入匹配的依赖项"。 - rhnoble
@CommonsWare 我在问题中添加了一个注释,我看到的冲突涉及到一个由于许可问题而无法上传的库。但它只是一个包含org.slf4j的本地jar文件。我遵循了您创建一个清晰项目、仅添加本地jar文件和logback-android-classic库作为依赖项的建议,但仍无法解决冲突问题。 - rhnoble
显示剩余4条评论
1个回答

0
我在我的“build.gradle”中添加了以下内容,以解决“slf4j”的传递依赖问题。这是排除依赖项的方法,使其不会被传递加载。并通过在“compile group”语句中明确提及来显式加载冲突的库。希望这可以帮到你。
configurations {
    all*.exclude group: 'ch.qos.logback'
    all*.exclude group: 'org.slf4j', module: 'jcl-over-slf4j'
    all*.exclude group: 'org.slf4j', module: 'jul-to-slf4j'
    all*.exclude group: 'org.slf4j', module: 'log4j-over-slf4j'
    all*.exclude group: 'org.slf4j', module: 'jcl-over-slf4j'
    all*.exclude group: 'org.slf4j', module: 'slf4j-log4j12'
    all*.exclude group: 'org.slf4j', module: 'slf4j-simple'
}

compile group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4j2Version
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: log4j2Version
compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: slf4jToLog4jVersion

我尝试了一下,但似乎没有任何效果,仍然出现与上述相同的错误。可能是我实现有误,我认为编译语句应该放在我的依赖块中,但不确定配置块应该放在哪里。我已经尝试将其放在build.gradle的基本级别和android{}块内部。 - rhnoble
是的,编译语句将放在依赖项块中,配置块将与依赖项级别处于同一级别。 - Ripu Daman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接