在更新到Android Studio 3.0并创建一个新项目之后,我注意到在build.gradle
中有一种新方法来添加新的依赖项而不是compile
有implementation
而不是testCompile
有testImplementation
。
例:
implementation 'com.android.support:appcompat-v7:25.0.0'
testImplementation 'junit:junit:4.12'
代替
compile 'com.android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
它们之间有什么区别,我应该使用什么?
tl;博士
只需更换:
compile
与implementation
(如果你不需要传递性)或api
(如果你需要传递性)testCompile
与testImplementation
debugCompile
与debugImplementation
androidTestCompile
与androidTestImplementation
compileOnly
仍然有效。它在3.0中添加以替换提供而不是编译。 (provided
在Gradle没有该用例的配置名称时引入,并在Maven提供的范围之后命名。)这是谷歌announced at IO17 Gradle 3.0带来的重大变化之一。
compile
配置是now deprecated,应该被implementation
或api
取代
dependencies { api 'commons-httpclient:commons-httpclient:3.1' implementation 'org.apache.commons:commons-lang3:3.5' }
api
配置中出现的依赖关系将传递给库的消费者,因此将出现在消费者的编译类路径中。另一方面,
implementation
配置中的依赖关系不会暴露给消费者,因此不会泄漏到消费者的编译类路径中。这有几个好处:
- 依赖关系不再泄漏到消费者的编译类路径中,因此您永远不会意外地依赖于传递依赖
- 由于减少了类路径大小,编译速度更快
- 当实现依赖性发生变化时,重新编译的次数减少:消费者不需要重新编译
- 清理发布:当与新的maven-publish插件结合使用时,Java库会生成POM文件,这些文件准确区分编译库所需的内容以及在运行时使用库所需的内容(换句话说,不要混合编译库本身所需的内容以及编译库所需的内容。
编译配置仍然存在,但不应该使用,因为它不会提供
api
和implementation
配置提供的保证。
注意:如果您只在应用程序模块中使用库(常见情况),您将不会注意到任何差异。 如果您有一个复杂的项目,模块相互依赖,或者您正在创建一个库,那么您将只能看到差异。
这个答案将展示implementation
,api
和compile
在项目中的区别。
假设我有一个包含三个Gradle模块的项目:
app
有myandroidlibrary
作为依赖。 myandroidlibrary
有myjavalibrary
作为依赖。
myjavalibrary
有一个MySecret
类
public class MySecret {
public static String getSecret() {
return "Money";
}
}
myandroidlibrary
有MyAndroidComponent
类操纵MySecret
类的价值。
public class MyAndroidComponent {
private static String component = MySecret.getSecret();
public static String getComponent() {
return "My component: " + component;
}
}
最后,app
只对myandroidlibrary
的价值感兴趣
TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());
现在,我们来谈谈依赖关系......
app
需要消耗:myandroidlibrary
,所以在app
build.gradle使用implementation
。
(注意:你也可以使用api / compile。但是请坚持一下。)
dependencies {
implementation project(':myandroidlibrary')
}
你觉得myandroidlibrary
build.gradle会是什么样子?我们应该使用哪个范围?
我们有三种选择:
dependencies {
// Option #1
implementation project(':myjavalibrary')
// Option #2
compile project(':myjavalibrary')
// Option #3
api project(':myjavalibrary')
}
它们之间有什么区别,我应该使用什么?
如果你正在使用compile
或api
。我们的Android应用程序现在能够访问myandroidcomponent
依赖项,这是一个MySecret
类。
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());
实施(选项#1)
如果您使用的是implementation
配置,则不会暴露MySecret
。
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile
那么,您应该选择哪种配置?这真的取决于你的要求。
如果要暴露依赖项,请使用api
或compile
。
如果您不想公开依赖项(隐藏内部模块),请使用implementation
。
注意:
这只是Gradle配置的要点,请参阅Table 49.1. Java Library plugin - configurations used to declare dependencies以获得更详细的解释。
这个答案的示例项目可以在https://github.com/aldoKelvianto/ImplementationVsCompile上找到
Compile
配置已被弃用,应由implementation
或api
取代。
您可以在https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation阅读文档。
简介部分是 -
标准Java插件和Java Library插件之间的主要区别在于后者引入了向消费者公开的API的概念。库是一个Java组件,旨在供其他组件使用。这是多项目构建中非常常见的用例,但只要您有外部依赖项。
该插件公开了两种可用于声明依赖关系的配置:api和实现。 api配置应该用于声明由库API导出的依赖项,而实现配置应该用于声明组件内部的依赖项。
简要解决方案
更好的方法是用compile
依赖项替换所有implementation
依赖项。只有泄漏模块接口的地方,才应该使用api
。这应该会导致更少的重新编译。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:25.4.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
// …
testImplementation 'junit:junit:4.12'
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
}
解释更多:
在Android Gradle插件3.0之前:我们遇到了一个很大的问题,即一个代码更改导致所有模块被重新编译。造成这种情况的根本原因是Gradle不知道您是否通过另一个模块泄漏模块的接口。
在Android Gradle插件3.0之后:最新的Android Gradle插件现在要求您明确定义是否泄漏模块的界面。基于此,它可以在应该重新编译的内容上做出正确的选择。
因此,compile
依赖项已被弃用,取而代之的是两个新的依赖项:
api
:你通过你自己的界面泄漏了这个模块的接口,这意味着与旧的compile
依赖关系完全相同implementation
:你只在内部使用这个模块,不会通过你的界面泄漏它因此,如果已使用模块的接口发生变化,您现在可以明确告诉Gradle重新编译模块。
由Jeroen Mols博客提供
外行人任期的短暂差异是:
阅读@aldok的答案以获得一个全面的例子。
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name | Role | Consumable? | Resolveable? | Description |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api | Declaring | no | no | This is where you should declare |
| | API | | | dependencies which are transitively |
| | dependencies | | | exported to consumers, for compile. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation | Declaring | no | no | This is where you should |
| | implementation | | | declare dependencies which are |
| | dependencies | | | purely internal and not |
| | | | | meant to be exposed to consumers. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly | Declaring compile | yes | yes | This is where you should |
| | only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at compile time, but should |
| | | | | not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly | Declaring | no | no | This is where you should |
| | runtime | | | declare dependencies which |
| | dependencies | | | are only required at runtime, |
| | | | | and not at compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies | no | no | This is where you |
| | | | | should declare dependencies |
| | | | | which are used to compile tests. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly | Declaring test | yes | yes | This is where you should |
| | compile only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at test compile time, |
| | | | | but should not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly | Declaring test | no | no | This is where you should |
| | runtime dependencies | | | declare dependencies which |
| | | | | are only required at test |
| | | | | runtime, and not at test compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+