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

本文翻译自:What's the difference between implementation and compile in Gradle?

After updating to Android Studio 3.0 and creating a new project, I noticed that in build.gradle there is a new way to add new dependencies instead of compile there is implementation and instead of testCompile there is testImplementation . 在更新到Android Studio 3.0并创建一个新项目之后,我注意到在build.gradle有一种新的方法来添加新的依赖项而不是compile implementation而不是testCompiletestImplementation

Example: 例:

 implementation 'com.android.support:appcompat-v7:25.0.0'
 testImplementation 'junit:junit:4.12'

instead of 代替

 compile 'com.android.support:appcompat-v7:25.0.0'
 testCompile 'junit:junit:4.12'

What's the difference between them and what should I be using? 它们之间有什么区别,我应该使用什么?


#1楼

参考:https://stackoom.com/question/30gl8/Gradle中的实现和编译之间有什么区别


#2楼

tl;dr TL;博士

Just replace: 只需更换:

  • compile with implementation (if you don't need transitivity) or api (if you need transitivity) implementation compile (如果你不需要传递性)或api (如果你需要传递性)
  • testCompile with testImplementation testCompile with testImplementation
  • debugCompile with debugImplementation debugCompile with debugImplementation
  • androidTestCompile with androidTestImplementation androidTestCompileandroidTestImplementation
  • compileOnly is still valid. compileOnly仍然有效。 It was added in 3.0 to replace provided and not compile. 它在3.0中添加以替换提供而不是编译。 ( provided introduced when Gradle didn't have a configuration name for that use-case and named it after Maven's provided scope.) provided推出的时候摇篮没有为用例配置名称后Maven的提供范围命名它。)

It is one of the breaking changes coming with Gradle 3.0 that Google announced at IO17 . 这是谷歌在IO17宣布的 Gradle 3.0带来的重大变化之一

The compile configuration is now deprecated and should be replaced by implementation or api compile配置现已弃用 ,应由implementationapi替换

From the Gradle documentation : Gradle文档

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

Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. 出现在api配置中的依赖关系将传递给库的消费者,因此将出现在消费者的编译类路径中。

Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. 另一方面,在implementation配置中找到的依赖关系不会暴露给消费者,因此不会泄漏到消费者的编译类路径中。 This comes with several benefits: 这有几个好处:

  • dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive dependency 依赖关系不再泄漏到消费者的编译类路径中,因此您永远不会意外地依赖于传递依赖
  • faster compilation thanks to reduced classpath size 由于减少了类路径大小,编译速度更快
  • less recompilations when implementation dependencies change: consumers would not need to be recompiled 当实现依赖性发生变化时,重新编译的次数减少:消费者不需要重新编译
  • cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don't mix what is needed to compile the library itself and what is needed to compile against the library). 清理发布:当与新的maven-publish插件结合使用时,Java库会生成POM文件,这些文件准确区分编译库所需的内容以及在运行时使用库所需的内容(换句话说,不要混合编译库本身所需的内容以及编译库所需的内容。

The compile configuration still exists, but should not be used as it will not offer the guarantees that the api and implementation configurations provide. 编译配置仍然存在,但不应使用,因为它不提供apiimplementation配置提供的保证。


Note: if you are only using a library in your app module -the common case- you won't notice any difference. 注意:如果您只在应用程序模块中使用库(常见情况),您将不会注意到任何差异。
you will only see the difference if you have a complex project with modules depending on each other, or you are creating a library. 如果您有一个复杂的项目,模块相互依赖,或者您正在创建一个库,那么您将只能看到差异。


#3楼

Compile configuration was deprecated and should be replaced by implementation or api . Compile配置已弃用,应由implementationapi替换。

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

The brief part being- 简介部分是 -

The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. 标准Java插件和Java Library插件之间的主要区别在于后者引入了向消费者公开的API的概念。 A library is a Java component meant to be consumed by other components. 库是一个Java组件,旨在供其他组件使用。 It's a very common use case in multi-project builds, but also as soon as you have external dependencies. 这是多项目构建中非常常见的用例,但只要您有外部依赖项。

The plugin exposes two configurations that can be used to declare dependencies: api and implementation. 该插件公开了两种可用于声明依赖关系的配置:api和实现。 The api configuration should be used to declare dependencies which are exported by the library API, whereas the implementation configuration should be used to declare dependencies which are internal to the component. api配置应该用于声明由库API导出的依赖项,而实现配置应该用于声明组件内部的依赖项。

For further explanation refer to this image. 有关进一步说明,请参阅此图像。 简要说明


#4楼

Brief Solution: 简要解决方案

The better approach is to replace all compile dependencies with implementation dependencies. 更好的方法是用implementation依赖项替换所有compile依赖项。 And only where you leak a module's interface, you should use api . 只有泄漏模块接口的地方,才应该使用api That should cause a lot less recompilation. 这应该会导致更少的重新编译。

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

Explain More: 解释更多:

Before Android Gradle plugin 3.0 : we had a big problem which is one code change causes all modules to be recompiled. 在Android Gradle插件3.0之前 :我们遇到了一个很大的问题,即一个代码更改导致所有模块被重新编译。 The root cause for this is that Gradle doesn't know if you leak the interface of a module through another one or not. 造成这种情况的根本原因是Gradle不知道您是否通过另一个模块泄漏模块的接口。

After Android Gradle plugin 3.0 : the latest Android Gradle plugin now requires you to explicitly define if you leak a module's interface. 在Android Gradle插件3.0之后 :最新的Android Gradle插件现在要求您明确定义是否泄漏模块的界面。 Based on that it can make the right choice on what it should recompile. 基于此,它可以在应该重新编译的内容上做出正确的选择。

As such the compile dependency has been deprecated and replaced by two new ones: 因此,不推荐使用compile依赖项,并将其替换为两个新的:

  • api : you leak the interface of this module through your own interface, meaning exactly the same as the old compile dependency api :你通过自己的接口泄漏了这个模块的接口,这意味着与旧的compile依赖项完全相同

  • implementation : you only use this module internally and does not leak it through your interface implementation :您只在内部使用此模块,不会通过您的界面泄漏它

So now you can explicitly tell Gradle to recompile a module if the interface of a used module changes or not. 因此,如果已使用模块的接口发生变化,您现在可以明确告诉Gradle重新编译模块。

Courtesy of Jeroen Mols blog Jeroen Mols博客提供


#5楼

This answer will demonstrate the difference between implementation , api , and compile on a project. 这个答案将演示项目的implementationapicompile之间的区别。


Let's say I have a project with three Gradle modules: 假设我有一个包含三个Gradle模块的项目:

  • app (an Android application) app(Android应用程序)
  • myandroidlibrary (an Android library) myandroidlibrary(一个Android库)
  • myjavalibrary (a Java library) myjavalibrary(一个Java库)

app has myandroidlibrary as dependencies. appmyandroidlibrary作为依赖项。 myandroidlibrary has myjavalibrary as dependencies. myandroidlibrarymyjavalibrary作为依赖。

依赖关系1

myjavalibrary has a MySecret class myjavalibrary有一个MySecret

public class MySecret {

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

myandroidlibrary has MyAndroidComponent class that manipulate value from MySecret class. myandroidlibrary具有MyAndroidComponent类,用于处理MySecret类的值。

public class MyAndroidComponent {

    private static String component = MySecret.getSecret();

    public static String getComponent() {
        return "My component: " + component;
    }    
}

Lastly, app is only interested in the value from myandroidlibrary 最后, app只对myandroidlibrary的价值myandroidlibrary

TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());

Now, let's talk about dependencies... 现在,我们来谈谈依赖关系......

app need to consume :myandroidlibrary , so in app build.gradle use implementation . app需要消费:myandroidlibrary ,所以在app build.gradle中使用implementation

( Note : You can use api/compile too. But hold that thought for a moment.) 注意 :你也可以使用api / compile。但是请坚持一下。)

dependencies {
    implementation project(':myandroidlibrary')      
}

Dependency2

What do you think myandroidlibrary build.gradle should look like? 您认为myandroidlibrary build.gradle会是什么样子? Which scope we should use? 我们应该使用哪个范围?

We have three options: 我们有三种选择:

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

Dependency3

What's the difference between them and what should I be using? 它们之间有什么区别,我应该使用什么?

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

If you're using compile or api . 如果你正在使用compileapi Our Android Application now able to access myandroidcomponent dependency, which is a MySecret class. 我们的Android应用程序现在能够访问myandroidcomponent依赖项,这是一个MySecret类。

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

Implementation (option #1) 实施(选项#1)

Dependency5

If you're using implementation configuration, MySecret is not exposed. 如果您正在使用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

So, which configuration you should choose? 那么,您应该选择哪种配置? That really depends on your requirement. 这真的取决于你的要求。

If you want to expose dependencies use api or compile . 如果要公开依赖项,请使用apicompile

If you don't want to expose dependencies (hiding your internal module) then use implementation . 如果您不想公开依赖项 (隐藏内部模块),请使用implementation

Note: 注意:

This is just a gist of Gradle configurations, refer to Table 49.1. 这只是Gradle配置的要点,请参阅表49.1。 Java Library plugin - configurations used to declare dependencies for more detailed explanation. Java Library插件 - 用于声明依赖关系的配置以获得更详细的说明。

The sample project for this answer is available on https://github.com/aldoKelvianto/ImplementationVsCompile 有关此答案的示例项目,请访问https://github.com/aldoKelvianto/ImplementationVsCompile


#6楼

The brief difference in layman's term is: 外行人任期的短暂差异是:

  • If you are working on an interface or module that provides support to other modules by exposing the members of the stated dependency you should be using 'api'. 如果您正在使用通过公开所述依赖项的成员来为其他模块提供支持的接口或模块,那么您应该使用“api”。
  • If you are making an application or module that is going to implement or use the stated dependency internally, use 'implementation'. 如果您要在内部实现或使用所述依赖项的应用程序或模块,请使用“实现”。
  • 'compile' worked same as 'api', however, if you are only implementing or using any library, 'implementation' will work better and save you resources. 'compile'与'api'的工作方式相同,但是,如果您只是实现或使用任何库,'实现'将更好地工作并节省您的资源。

read the answer by @aldok for a comprehensive example. 阅读@aldok的答案以获得一个全面的例子。

发布了0 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/p15097962069/article/details/105379270