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

问题描述 投票:747回答:6

在更新到Android Studio 3.0并创建一个新项目之后,我注意到在build.gradle中有一种新方法来添加新的依赖项而不是compileimplementation而不是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'

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

gradle build.gradle dependency-management gradle-plugin transitive-dependency
6个回答
1021
投票

tl;博士

只需更换:

  • compileimplementation(如果你不需要传递性)或api(如果你需要传递性)
  • testCompiletestImplementation
  • debugCompiledebugImplementation
  • androidTestCompileandroidTestImplementation
  • compileOnly仍然有效。它在3.0中添加以替换提供而不是编译。 (provided在Gradle没有该用例的配置名称时引入,并在Maven提供的范围之后命名。)

这是谷歌announced at IO17 Gradle 3.0带来的重大变化之一。

compile配置是now deprecated,应该被implementationapi取代

来自Gradle documentation

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

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

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

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

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


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


260
投票

这个答案将展示implementationapicompile在项目中的区别。


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

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

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

Dependency1

myjavalibrary有一个MySecret

public class MySecret {

    public static String getSecret() {
        return "Money";
    }
}

myandroidlibraryMyAndroidComponent类操纵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')      
}

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配置的要点,请参阅Table 49.1. Java Library plugin - configurations used to declare dependencies以获得更详细的解释。

这个答案的示例项目可以在https://github.com/aldoKelvianto/ImplementationVsCompile上找到


58
投票

Compile配置已被弃用,应由implementationapi取代。

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

简介部分是 -

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

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

有关进一步说明,请参阅此图像。 Brief explanation


43
投票

简要解决方案

更好的方法是用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博客提供


6
投票

外行人任期的短暂差异是:

  • 如果您正在使用通过公开所述依赖项的成员来为其他模块提供支持的接口或模块,那么您应该使用“api”。
  • 如果您要在内部实现或使用所述依赖项的应用程序或模块,请使用“实现”。
  • 'compile'与'api'的工作方式相同,但是,如果您只是实现或使用任何库,'实现'将更好地工作并节省您的资源。

阅读@aldok的答案以获得一个全面的例子。


-1
投票
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| 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.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
© www.soinside.com 2019 - 2024. All rights reserved.