协慌网

登录 贡献 社区

Gradle 中的实现和编译之间有什么区别?

在更新到 Android Studio 3.0 并创建一个新项目之后,我注意到在build.gradle有一种新的方法来添加新的依赖项而不是compile implementation而不是testCompiletestImplementation

例:

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
  • androidTestCompileandroidTestImplementation
  • compileOnly仍然有效。它在 3.0 中添加以替换提供而不是编译。 ( provided推出的时候摇篮没有为用例配置名称后 Maven 的提供范围命名它。)

这是谷歌在 IO17 宣布的 Gradle 3.0 带来的重大变化之一

compile配置现已弃用 ,应由implementationapi替换

Gradle 文档

dependencies {
    api 'commons-httpclient:commons-httpclient:3.1'
    implementation 'org.apache.commons:commons-lang3:3.5'
}

出现在api配置中的依赖关系将传递给库的消费者,因此将出现在消费者的编译类路径中。

另一方面,在implementation配置中找到的依赖关系不会暴露给消费者,因此不会泄漏到消费者的编译类路径中。这有几个好处:

  • 依赖关系不再泄漏到消费者的编译类路径中,因此您永远不会意外地依赖于传递依赖
  • 由于减少了类路径大小,编译速度更快
  • 当实现依赖性发生变化时,重新编译的次数减少:消费者不需要重新编译
  • 清理发布:当与新的 maven-publish 插件结合使用时,Java 库会生成 POM 文件,这些文件准确区分编译库所需的内容以及在运行时使用库所需的内容(换句话说,不要混合编译库本身所需的内容以及编译库所需的内容。

编译配置仍然存在,但不应使用,因为它不提供apiimplementation配置提供的保证。


注意:如果您只在应用程序模块中使用库(常见情况),您将不会注意到任何差异。
如果您有一个复杂的项目,模块相互依赖,或者您正在创建一个库,那么您将只能看到差异。

这个答案将演示项目的implementationapicompile之间的区别。


假设我有一个包含三个 Gradle 模块的项目:

  • app(Android 应用程序)
  • myandroidlibrary(一个 Android 库)
  • myjavalibrary(一个 Java 库)

appmyandroidlibrary作为依赖项。 myandroidlibrarymyjavalibrary作为依赖。

依赖关系1

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')      
}

Dependency2

您认为myandroidlibrary build.gradle 会是什么样子?我们应该使用哪个范围?

我们有三种选择:

dependencies {
    // Option #1
    implementation project(':myjavalibrary') 
    // Option #2
    compile project(':myjavalibrary')      
    // Option #3
    api project(':myjavalibrary')           
}

Dependency3

它们之间有什么区别,我应该使用什么?

编译或 Api(选项#2 或#3) Dependency4

如果你正在使用compileapi 。我们的 Android 应用程序现在能够访问myandroidcomponent依赖项,这是一个MySecret类。

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());

实施(选项#1)

Dependency5

如果您正在使用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

那么,您应该选择哪种配置?这真的取决于你的要求。

如果要公开依赖项,请使用apicompile

如果您不想公开依赖项 (隐藏内部模块),请使用implementation

注意:

这只是 Gradle 配置的要点,请参阅表 49.1。 Java Library 插件 - 用于声明依赖关系的配置以获得更详细的说明。

有关此答案的示例项目,请访问https://github.com/aldoKelvianto/ImplementationVsCompile

Compile配置已弃用,应由implementationapi替换。

您可以在https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation 上阅读文档。

简介部分是 -

标准 Java 插件和 Java Library 插件之间的主要区别在于后者引入了向消费者公开的 API 的概念。库是一个 Java 组件,旨在供其他组件使用。这是多项目构建中非常常见的用例,但只要您有外部依赖项。

该插件公开了两种可用于声明依赖关系的配置:api 和实现。 api 配置应该用于声明由库 API 导出的依赖项,而实现配置应该用于声明组件内部的依赖项。

有关进一步说明,请参阅此图像。 简要说明