在更新到Android Studio 3.0并创建一个新项目后,我注意到在构建中。gradle有一种新方法来添加新的依赖项,而不是compile,而是implementation,而不是testCompile,而是testimplemimplementation。

例子:

 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'

它们之间的区别是什么,我应该用什么?


当前回答

其他答案解释了这种差异。

只要确保对于Kotlin DSL (build.gradle.kts),函数应该有圆括号,它们的字符串参数应该用双引号括起来,而不是单引号:

Groovy (build.gradle) 实现“com.android.support: appcompat-v7:25.0.0” testImplementation“junit: junit: 4.12” 芬兰湾的科特林(build.gradle.kts) 实现(“com.android.support: appcompat-v7:25.0.0”) testImplementation(“junit: junit: 4.12”)

其他回答

implementation: mostly we use implementation configuration. It hides the internal dependency of the module to its consumer to avoid accidental use of any transitive dependency, hence faster compilation and less recompilation. api: must be used very carefully, since it leaks the to consumer’s compile classpath, hence misusing of api could lead to dependency pollution. compileOnly: when we don’t need any dependency at runtime, since compileOnly dependency won’t become the part of the final build. we will get a smaller build size. runtimeOnly: when we want to change or swap the behaviour of the library at runtime (in final build).

我已经创建了一个深入了解每个工作示例的帖子:源代码

https://medium.com/@gauraw.negi/how-gradle-dependency-configurations-work-underhood-e934906752e5

当你在gradle项目中声明一个依赖项时 代码库+它的依赖关系(声明为api)可以被gradle项目的消费者使用。

让我们举个例子

我们有一级,二级,三级gradle项目。

Level 1使用Level 2。Level 2使用Level 3。

一级<-二级<-三级

使用API和实现,我们可以控制是否应该将级别3的类公开到级别1。

这如何使构建更快:

关卡3的任何变化。不需要重新编译级别1。 特别是在开发过程中,节省时间。

这个答案将演示项目中的实现、api和编译之间的区别。


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

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

应用程序有myandroidlibrary作为依赖项。Myandroidlibrary有myjavlibrary作为依赖项。

myjavlibrary有一个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());

现在,让我们谈谈依赖关系……

应用需要消耗:myandroidlibrary,所以在应用构建中。Gradle使用实现。

(注意:你也可以使用api/compile。但请稍等片刻。)

dependencies {
    implementation project(':myandroidlibrary')      
}

你认为myandroidlibrary构建了什么?Gradle应该是什么样子?我们应该使用哪个作用域?

我们有三个选择:

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

它们之间的区别是什么,我应该用什么?

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

如果你使用的是编译器或者api。我们的Android应用现在可以访问myandroidcomponent依赖,这是一个MySecret类。

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

实现(选项#1)

如果您正在使用实现配置,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。

如果你不想公开依赖关系(隐藏你的内部模块),那么使用实现。

注意:

这只是Gradle配置的一个要点,参见表49.1。Java库插件-用于声明依赖关系的配置,以获得更详细的解释。

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

简单的解决方案:

更好的方法是用实现依赖替换所有编译依赖。只有在泄露模块接口时,才应该使用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:你通过你自己的接口泄露了这个模块的接口,这意味着和旧的编译依赖完全一样 实现:你只在内部使用这个模块,不会通过你的接口泄露它

所以现在你可以显式地告诉Gradle重新编译一个模块,如果使用的模块的接口改变与否。

由Jeroen Mols博客提供

门外汉术语的简单区别是:

如果你正在处理一个接口或模块,它通过公开所声明的依赖关系的成员来为其他模块提供支持,你应该使用'api'。 如果你正在创建一个应用程序或模块,要在内部实现或使用声明的依赖项,请使用'implementation'。 'compile'与'api'工作方式相同,但是,如果你只是实现或使用任何库,'implementation'将更好地工作并节省资源。

阅读@aldok的回答以获得一个全面的示例。