Gradle Implementation vs API配置

时间:2017-06-07 13:23:32

标签: android gradle dependencies implementation

我正在尝试弄清楚构建我的依赖项时apiimplementation配置之间的区别。
在文档中,它说implementation有更好的构建时间,但是, 在一个类似的问题中看到这个comment,我想知道它是否属实 由于我不是gradle的专家,我希望有人可以提供帮助。我已经阅读了documentation,但我想知道一个易于理解的解释。

6 个答案:

答案 0 :(得分:276)

Gradle compile关键字已弃用,以支持apiimplementation关键字来配置依赖关系。

使用api相当于使用已弃用的compile,因此如果您将所有compile替换为api,一切都会一如既往。

要了解implementation关键字,请考虑以下示例。

示例

假设您有一个名为MyLibrary的库,它在内部使用另一个名为InternalLibrary的库。像这样:

    // 'InternalLibrary' module
    public class InternalLibrary {
        public static String giveMeAString(){
            return "hello";
        }
    }
    // 'MyLibrary' module
    public class MyLibrary {
        public String myString(){
            return InternalLibrary.giveMeAString();
        }
    }

假设MyLibrary build.gradleapi中使用dependencies{}配置,如下所示:

dependencies {
    api project(':InternalLibrary')
}

您希望在代码中使用MyLibrary,因此在您的应用build.gradle中添加此依赖项:

dependencies {
    api project(':MyLibrary')
}

使用api配置(或已弃用的compile),您可以在应用代码中访问MyLibraryInternalLibrary

// Access 'MyLibrary' (as desired and expected)
MyLibrary myLib = new MyLibrary();
System.out.println(myLib.myString());

// Can ALSO access the internal library too (and you shouldn't)
System.out.println(InternalLibrary.giveMeAString());

通过这种方式,模块MyLibrary可能会“泄漏”某些内部实现。您不应该(能够)使用它,因为它不是由您直接导入的。

引入了implementation配置以防止这种情况发生。 现在,如果您在implementation中使用api而不是MyLibrary

dependencies {
    implementation project(':InternalLibrary')
}

在你的应用中build.gradle

dependencies {
    implementation project(':MyLibrary')
}

您将无法再在应用代码中拨打InternalLibrary.giveMeAString()

请注意,如果MyLibrary使用api导入InternalLibrary,您的应用能够毫无问题地致电InternalLibrary.giveMeAString(),无需使用apiimplementationMyLibrary添加到您的应用中。

这种拳击策略允许Android Gradle插件知道如果您在InternalLibrary中编辑某些内容以仅触发MyLibrary的重新编译而不会触发重新编译整个应用程序,因为您不知道可以访问InternalLibrary

当你有很多嵌套依赖项时,这种机制可以大大加快构建速度。 (观看最后链接的视频,以便全面了解这一点)

<强>结论

  • 当您切换到新的Android Gradle插件3.X.X时,您应该用compile关键字(1 *)替换所有implementation。然后尝试编译和测试您的应用程序。如果一切正常,请保留代码,如果您遇到问题,可能是您的依赖项有问题,或者您使用了现在是私有且无法访问的内容。 Android Gradle插件工程师Jerome Dochez的建议(1 )*

  • 如果您是库管理员,则应使用api作为库的公共API所需的每个依赖项,而使用implementation作为测试依赖项或依赖项,而不是最终用户使用。

Useful article展示实施 api

之间的区别

<强>参考 (这是为节省时间而拆分的视频)

Google I/O 2017 - How speed up Gradle builds (FULL VIDEO)

Google I/O 2017 - How speed up Gradle builds (NEW GRADLE PLUGIN 3.0.0 PART ONLY)

Google I/O 2017 - How speed up Gradle builds (reference to 1*)

Android documentation

答案 1 :(得分:64)

我喜欢将api依赖关系视为公开(由其他模块看到),而implementation依赖关系为私有(仅限于这个模块)。

请注意,与public / private变量和方法不同,运行时不会强制执行api / implementation个依赖项。这只是一个构建时优化,它允许Gradle知道当其中一个依赖项更改其API时需要重新编译的模块。

答案 2 :(得分:5)

来自@matpag@dev-bmax的答案非常清楚,足以使人们理解实现和api之间的不同用法。我只想从另一个角度做一个额外的解释,希望对有同样问题的人们有所帮助。

我创建了两个测试项目:

  • 项目A 作为名为'frameworks-web-gradle-plugin'的java库项目,取决于'org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE'
  • 项目B 通过实施'com.example.frameworks.gradle:frameworks-web-gradle-plugin:0.0.1-SNAPSHOT'依赖项目A

上面描述的依赖关系层次结构如下:

[project-b]-> [project-a]-> [spring-boot-gradle-plugin]

然后我测试了以下方案:

  1. 通过实现来使项目A取决于'org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE'。

    在终端B的根目录中运行gradle dependencies命令,通过以下输出屏幕截图,我们可以看到'spring-boot-gradle-plugin'出现在runtimeClasspath依赖关系树中,而不是出现在compileClasspath的树中这就是为什么我们不能使用通过实现声明的库的原因,只是不能通过编译实现。

    enter image description here

  2. 使项目A取决于 api

    的'org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE'

    再次在终端中输入B根目录,运行gradle dependencies命令。 现在,“ spring-boot-gradle-plugin”同时出现在compileClasspath和runtimeClasspath依赖关系树中。

    enter image description here

我注意到的一个重要区别是,以实现方式声明的生产者/库项目中的依赖项不会出现在使用者项目的compileClasspath中,因此我们不能在使用者项目中使用相应的lib。

答案 3 :(得分:3)

请考虑使用JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("document.getElementById('//id of element').setAttribute('value', '//value to set')"); // to click js.executeScript("arguments[0].click();", element); 模块,该模块使用app作为库,lib1使用lib1作为库。像这样的东西:lib2

现在在app -> lib1 -> lib2中使用api lib2时,则lib1 在使用app或{{时可以看到 lib2代码1}}。

但是在api lib1中使用implementation lib1时,则app 看不到 implementation lib2代码。

答案 4 :(得分:3)

来自gradle documentation

让我们看一下基于JVM的项目的非常简单的构建脚本。

plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.hibernate:hibernate-core:3.6.7.Final'
    api 'com.google.guava:guava:23.0'
    testImplementation 'junit:junit:4.+'
}

实施

编译项目生产源所需的依赖关系,这些依赖关系不是项目公开的API的一部分。例如,该项目将Hibernate用于其内部持久层实现。

api

编译项目生产源所需的依赖关系,这些依赖关系是项目公开的API的一部分。例如,该项目使用Guava,并在其方法签名中公开带有Guava类的公共接口。

答案 5 :(得分:0)

现在documentation中有很好的解释

<块引用>

api 配置应该用于声明依赖项,这些依赖项是 由库 API 导出,而实现配置 应该用于声明内部的依赖项 组件。