Android X + Truth + Guava 测试编译问题
Android X + Truth + Guava test compile issue
我有一个 Android 库(称为 api
)gradle 模块作为一个更大项目的一部分。我刚刚将整个项目迁移到 AndroidX。我现在在 api
lib:
上进行 运行 仪器测试时出现此错误
Task :api:checkDebugAndroidTestDuplicateClasses FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':api:checkDebugAndroidTestDuplicateClasses'.
> 1 exception was raised by workers:
java.lang.RuntimeException: java.lang.RuntimeException: Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-25.1-android.jar (com.google.guava:guava:25.1-android) and listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)
如果我检查 debugAndroidTest
变体的运行时 class 路径:
./gradlew api:dependencies --configuration debugAndroidTestRuntimeClasspath | grep --color -E "guava|$"
我得到了这个输出。我可以看到问题:
------------------------------------------------------------
Project :api
------------------------------------------------------------
debugAndroidTestRuntimeClasspath - Resolved configuration for runtime for variant: debugAndroidTest
+--- project :test_utils
| +--- project :core
...
| +--- project :api (*)
| +--- com.google.android.material:material:1.1.0-alpha03
| | +--- androidx.annotation:annotation:1.0.1 -> 1.1.0-alpha01
| | +--- androidx.appcompat:appcompat:1.1.0-alpha01
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0-alpha01
| | | +--- androidx.core:core:1.1.0-alpha01 -> 1.1.0-alpha03
| | | | +--- com.google.guava:listenablefuture:1.0 // <------ GUAVA
| | | | +--- androidx.annotation:annotation:1.0.1 -> 1.1.0-alpha01
...
+--- com.google.truth:truth:0.42
| +--- com.google.guava:guava:25.1-android / <------ MORE GUAVA
| | +--- com.google.code.findbugs:jsr305:3.0.2
| | +--- com.google.errorprone:error_prone_annotations:2.1.3 -> 2.3.1
| | +--- com.google.j2objc:j2objc-annotations:1.1
| | \--- org.codehaus.mojo:animal-sniffer-annotations:1.14
| +--- org.checkerframework:checker-compat-qual:2.5.3
| +--- org.checkerframework:checker-qual:2.5.3
| +--- junit:junit:4.12 (*)
| +--- com.googlecode.java-diff-utils:diffutils:1.3.0
| +--- com.google.auto.value:auto-value-annotations:1.6.2
| \--- com.google.errorprone:error_prone_annotations:2.3.1
...
AndroidX 核心依赖于 guava 的新 "ListableFuture-only" 构建,而 Truth 依赖于完整的 Guava 25。
我想我了解 ListenableFuture 的潜在问题:https://groups.google.com/forum/#!topic/guava-announce/Km82fZG68Sw
此处正确的解决方案是什么?
我不想将 Guava 完全排除在 Truth 之外(否则 Truth 无法编译)
androidTestImplementation("com.google.truth:truth:0.42") {
exclude group: 'com.google.guava', module: 'guava'
}
我可以通过将 Guava 27 设为一级依赖来排除 + 强制更新它吗:
androidTestImplementation("com.google.truth:truth:$rootProject.ext.truthVersion") {
exclude group: 'com.google.guava', module: 'guava'
}
// must add guava as top level dependency to force Truth to use latest version
androidTestImplementation 'com.google.guava:guava:27.0.1-android'
如果我这样做,我应该使用 android 还是 JRE 版本的番石榴?
附带问题:
为什么我在查看 compile
classpath 时看不到 guava 依赖项?该错误是编译时错误,不是运行时错误
./gradlew api:dependencies --configuration debugAndroidTestCompileClasspath | grep --color -E "guava|$"
结果部门:
debugAndroidTestCompileClasspath - Resolved configuration for compilation for variant: debugAndroidTest
+--- project :test_utils // <----------- why are test_utils deps not listed here???
...
+--- com.google.truth:truth:0.42
| +--- com.google.guava:guava:25.1-android <------ GUAVA
| | +--- com.google.code.findbugs:jsr305:3.0.2
| | +--- org.checkerframework:checker-compat-qual:2.0.0 -> 2.5.3
| | +--- com.google.errorprone:error_prone_annotations:2.1.3 -> 2.3.1
| | +--- com.google.j2objc:j2objc-annotations:1.1
| | \--- org.codehaus.mojo:animal-sniffer-annotations:1.14
| +--- org.checkerframework:checker-compat-qual:2.5.3
| +--- org.checkerframework:checker-qual:2.5.3
| +--- junit:junit:4.12 (*)
| +--- com.googlecode.java-diff-utils:diffutils:1.3.0
| +--- com.google.auto.value:auto-value-annotations:1.6.2
| \--- com.google.errorprone:error_prone_annotations:2.3.1
...
+--- com.google.truth:truth:{strictly 0.42} -> 0.42 (c)
+--- com.google.guava:guava:{strictly 25.1-android} -> 25.1-android (c) // <--------- why is this listed again here at top level?
更新:
更新到 Truth 0.43 后,我现在看到这个错误:
> Could not resolve all artifacts for configuration ':mymodule:debugAndroidTestRuntimeClasspath'.
> Could not resolve com.google.guava:listenablefuture:{strictly 1.0}.
Required by:
project :mymodule
> Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'andrexampleoidx.core:core:1.1.0-alpha04' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
> Could not resolve com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava.
Required by:
project :mymodule > com.google.truth:truth:0.43 > com.google.guava:guava:27.0.1-android
> Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'com.google.guava:listenablefuture:1.0'
...
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
> Could not resolve com.google.guava:listenablefuture:1.0.
Required by:
project :mymodule > androidx.core:core:1.1.0-alpha04
project :mymodule > androidx.concurrent:concurrent-futures:1.0.0-alpha02
> Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
如果我理解正确的话:
- 真相0.43取决于Guava 27
- Guava 27 依赖于
9999.0-empty
,因为它 内部 包含 ListenableFuture
的副本并且版本 9999.0-empty 很好 "empty"。
- 其他库如 AndroidX 核心依赖于
listenablefuture:1.0
- 解决冲突时(我应该使用版本 1.0 还是 9999.0?)Gradle 将选择最新版本,在本例中为 9999.0。
- 所以 AndroidX 核心 实际上 通过 Guava 从 class 路径获取
ListenableFuture
,但它是 none-the -更聪明。
- 但是,
strictly
关键字强制使用 1.0
- 这是因为 Android Gradle 插件强制运行时和编译时 class 路径依赖于相同的版本 =( read more here
所以现在我不知道该怎么做。
类似的东西应该可以防止重复:
implementation ("com.google.android.material:material:1.1.0-alpha03") {
exclude group: "com.google.guava", module: "listenablefuture"
}
更新库的部分似乎是正确的:
androidTestImplementation "com.google.guava:guava:27.0.1-android"
androidTestImplementation ("com.google.truth:truth:0.42") {
exclude group: "com.google.guava", module: "guava"
}
只能假定没有 build.gradle
。
要解决冲突,只需添加对 Guava 27 的依赖就足够了。这样做应该会自动(尽管 the post you linked 中描述的 "Version 99 Does Not Exist" hack)防止 ListenableFuture
的第二个副本被拉入。(如果没有,请告诉我们!)
由于您在 Android 库上工作,听起来您想要 guava-27.0.1-android
而不是 -jre
。
我对你的附带问题一无所知,抱歉。很抱歉这么长时间没有回复。
另一件可能 "work" 的事情是让您的应用程序本身(不仅仅是测试,而是整个应用程序)依赖于 guava:27.0.1-android
。如果您的构建使用 Proguard,它应该在构建期间全部被删除(ListenableFuture
除外)。如果你不是,那么 Guava 是一个很大的依赖,特别是为了解决我们的 listenablefuture
技巧和随后的 Android Gradle 插件之间的不良交互: (
我遇到了相同(或类似?)的问题,在我这边看来是我同时使用了 androidx.test.ext:truth
和 com.google.truth:truth
。解决第一个问题使问题消失,因为它们在内部依赖于相同库的不同版本。
我有一个 Android 库(称为 api
)gradle 模块作为一个更大项目的一部分。我刚刚将整个项目迁移到 AndroidX。我现在在 api
lib:
Task :api:checkDebugAndroidTestDuplicateClasses FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':api:checkDebugAndroidTestDuplicateClasses'.
> 1 exception was raised by workers:
java.lang.RuntimeException: java.lang.RuntimeException: Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-25.1-android.jar (com.google.guava:guava:25.1-android) and listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)
如果我检查 debugAndroidTest
变体的运行时 class 路径:
./gradlew api:dependencies --configuration debugAndroidTestRuntimeClasspath | grep --color -E "guava|$"
我得到了这个输出。我可以看到问题:
------------------------------------------------------------
Project :api
------------------------------------------------------------
debugAndroidTestRuntimeClasspath - Resolved configuration for runtime for variant: debugAndroidTest
+--- project :test_utils
| +--- project :core
...
| +--- project :api (*)
| +--- com.google.android.material:material:1.1.0-alpha03
| | +--- androidx.annotation:annotation:1.0.1 -> 1.1.0-alpha01
| | +--- androidx.appcompat:appcompat:1.1.0-alpha01
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0-alpha01
| | | +--- androidx.core:core:1.1.0-alpha01 -> 1.1.0-alpha03
| | | | +--- com.google.guava:listenablefuture:1.0 // <------ GUAVA
| | | | +--- androidx.annotation:annotation:1.0.1 -> 1.1.0-alpha01
...
+--- com.google.truth:truth:0.42
| +--- com.google.guava:guava:25.1-android / <------ MORE GUAVA
| | +--- com.google.code.findbugs:jsr305:3.0.2
| | +--- com.google.errorprone:error_prone_annotations:2.1.3 -> 2.3.1
| | +--- com.google.j2objc:j2objc-annotations:1.1
| | \--- org.codehaus.mojo:animal-sniffer-annotations:1.14
| +--- org.checkerframework:checker-compat-qual:2.5.3
| +--- org.checkerframework:checker-qual:2.5.3
| +--- junit:junit:4.12 (*)
| +--- com.googlecode.java-diff-utils:diffutils:1.3.0
| +--- com.google.auto.value:auto-value-annotations:1.6.2
| \--- com.google.errorprone:error_prone_annotations:2.3.1
...
AndroidX 核心依赖于 guava 的新 "ListableFuture-only" 构建,而 Truth 依赖于完整的 Guava 25。
我想我了解 ListenableFuture 的潜在问题:https://groups.google.com/forum/#!topic/guava-announce/Km82fZG68Sw
此处正确的解决方案是什么?
我不想将 Guava 完全排除在 Truth 之外(否则 Truth 无法编译)
androidTestImplementation("com.google.truth:truth:0.42") {
exclude group: 'com.google.guava', module: 'guava'
}
我可以通过将 Guava 27 设为一级依赖来排除 + 强制更新它吗:
androidTestImplementation("com.google.truth:truth:$rootProject.ext.truthVersion") {
exclude group: 'com.google.guava', module: 'guava'
}
// must add guava as top level dependency to force Truth to use latest version
androidTestImplementation 'com.google.guava:guava:27.0.1-android'
如果我这样做,我应该使用 android 还是 JRE 版本的番石榴?
附带问题:
为什么我在查看 compile
classpath 时看不到 guava 依赖项?该错误是编译时错误,不是运行时错误
./gradlew api:dependencies --configuration debugAndroidTestCompileClasspath | grep --color -E "guava|$"
结果部门:
debugAndroidTestCompileClasspath - Resolved configuration for compilation for variant: debugAndroidTest
+--- project :test_utils // <----------- why are test_utils deps not listed here???
...
+--- com.google.truth:truth:0.42
| +--- com.google.guava:guava:25.1-android <------ GUAVA
| | +--- com.google.code.findbugs:jsr305:3.0.2
| | +--- org.checkerframework:checker-compat-qual:2.0.0 -> 2.5.3
| | +--- com.google.errorprone:error_prone_annotations:2.1.3 -> 2.3.1
| | +--- com.google.j2objc:j2objc-annotations:1.1
| | \--- org.codehaus.mojo:animal-sniffer-annotations:1.14
| +--- org.checkerframework:checker-compat-qual:2.5.3
| +--- org.checkerframework:checker-qual:2.5.3
| +--- junit:junit:4.12 (*)
| +--- com.googlecode.java-diff-utils:diffutils:1.3.0
| +--- com.google.auto.value:auto-value-annotations:1.6.2
| \--- com.google.errorprone:error_prone_annotations:2.3.1
...
+--- com.google.truth:truth:{strictly 0.42} -> 0.42 (c)
+--- com.google.guava:guava:{strictly 25.1-android} -> 25.1-android (c) // <--------- why is this listed again here at top level?
更新:
更新到 Truth 0.43 后,我现在看到这个错误:
> Could not resolve all artifacts for configuration ':mymodule:debugAndroidTestRuntimeClasspath'.
> Could not resolve com.google.guava:listenablefuture:{strictly 1.0}.
Required by:
project :mymodule
> Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'andrexampleoidx.core:core:1.1.0-alpha04' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
> Could not resolve com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava.
Required by:
project :mymodule > com.google.truth:truth:0.43 > com.google.guava:guava:27.0.1-android
> Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'com.google.guava:listenablefuture:1.0'
...
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
> Could not resolve com.google.guava:listenablefuture:1.0.
Required by:
project :mymodule > androidx.core:core:1.1.0-alpha04
project :mymodule > androidx.concurrent:concurrent-futures:1.0.0-alpha02
> Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
...
如果我理解正确的话:
- 真相0.43取决于Guava 27
- Guava 27 依赖于
9999.0-empty
,因为它 内部 包含ListenableFuture
的副本并且版本 9999.0-empty 很好 "empty"。 - 其他库如 AndroidX 核心依赖于
listenablefuture:1.0
- 解决冲突时(我应该使用版本 1.0 还是 9999.0?)Gradle 将选择最新版本,在本例中为 9999.0。
- 所以 AndroidX 核心 实际上 通过 Guava 从 class 路径获取
ListenableFuture
,但它是 none-the -更聪明。 - 但是,
strictly
关键字强制使用 1.0 - 这是因为 Android Gradle 插件强制运行时和编译时 class 路径依赖于相同的版本 =( read more here
所以现在我不知道该怎么做。
类似的东西应该可以防止重复:
implementation ("com.google.android.material:material:1.1.0-alpha03") {
exclude group: "com.google.guava", module: "listenablefuture"
}
更新库的部分似乎是正确的:
androidTestImplementation "com.google.guava:guava:27.0.1-android"
androidTestImplementation ("com.google.truth:truth:0.42") {
exclude group: "com.google.guava", module: "guava"
}
只能假定没有 build.gradle
。
要解决冲突,只需添加对 Guava 27 的依赖就足够了。这样做应该会自动(尽管 the post you linked 中描述的 "Version 99 Does Not Exist" hack)防止 ListenableFuture
的第二个副本被拉入。(如果没有,请告诉我们!)
由于您在 Android 库上工作,听起来您想要 guava-27.0.1-android
而不是 -jre
。
我对你的附带问题一无所知,抱歉。很抱歉这么长时间没有回复。
另一件可能 "work" 的事情是让您的应用程序本身(不仅仅是测试,而是整个应用程序)依赖于 guava:27.0.1-android
。如果您的构建使用 Proguard,它应该在构建期间全部被删除(ListenableFuture
除外)。如果你不是,那么 Guava 是一个很大的依赖,特别是为了解决我们的 listenablefuture
技巧和随后的 Android Gradle 插件之间的不良交互: (
我遇到了相同(或类似?)的问题,在我这边看来是我同时使用了 androidx.test.ext:truth
和 com.google.truth:truth
。解决第一个问题使问题消失,因为它们在内部依赖于相同库的不同版本。