在更新到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'

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


当前回答

简单的解决方案:

更好的方法是用实现依赖替换所有编译依赖。只有在泄露模块接口时,才应该使用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的回答以获得一个全面的示例。

这个答案将演示项目中的实现、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博客提供

+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| 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.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+

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

只要确保对于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”)