在更新到 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; 博士
只需更换:
implementation
compile
testCompile
with testImplementation
debugCompile
with debugImplementation
androidTestCompile
与androidTestImplementation
compileOnly
仍然有效。它在 3.0 中添加以替换提供而不是编译。 ( provided
推出的时候摇篮没有为用例配置名称后 Maven 的提供范围命名它。) 这是谷歌在 IO17 宣布的 Gradle 3.0 带来的重大变化之一 。
compile
配置现已弃用 ,应由implementation
或api
替换
从Gradle 文档 :
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
的价值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 配置的要点,请参阅表 49.1。 Java Library 插件 - 用于声明依赖关系的配置以获得更详细的说明。
有关此答案的示例项目,请访问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 导出的依赖项,而实现配置应该用于声明组件内部的依赖项。