[gradle] Gradle에서 구현과 컴파일의 차이점은 무엇입니까?

안드로이드 스튜디오 3.0으로 업데이트하고 새 프로젝트를 생성 한 후, 나는있는 것으로 나타났습니다 build.gradle대신 새로운 종속성을 추가 할 수있는 새로운 방법이 compile존재 implementation하고 대신 testCompile있다 testImplementation.

예:

 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'

그들 사이의 차이점은 무엇이며 어떻게 사용해야합니까?



답변

tl; dr

그냥 교체하십시오 :

  • compilewith implementation(transitivity가 필요하지 않은 경우) 또는 api(transitivity가 필요한 경우)
  • testCompiletestImplementation
  • debugCompiledebugImplementation
  • androidTestCompileandroidTestImplementation
  • compileOnly여전히 유효합니다. 제공된 3.0을 대체하고 컴파일하지 않기 위해 3.0에 추가되었습니다. ( providedGradle에 해당 사용 사례에 대한 구성 이름이없고 Maven이 제공 한 범위에 따라 이름을 지정할 때 도입되었습니다.)

구글 이 IO17에서 발표 한 것은 Gradle 3.0과 함께 제공되는 주요 변경 사항 중 하나입니다 .

compile구성되어 지금은 사용되지 않는 및 교체해야 implementation하거나api

로부터 Gradle을 문서 :

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

api구성에 나타나는 종속성 은 라이브러리 소비자에게 전 이적으로 노출되며 소비자의 컴파일 클래스 경로에 나타납니다.

implementation반면에 구성 에서 발견 된 종속성 은 소비자에게 노출되지 않으므로 소비자의 컴파일 클래스 경로로 누출되지 않습니다. 여기에는 몇 가지 이점이 있습니다.

  • 종속성이 더 이상 소비자의 컴파일 클래스 경로로 누출되지 않으므로 실수로 전 이적 종속성에 의존하지 않습니다.
  • 클래스 경로 크기 감소로 인한 빠른 컴파일
  • 구현 종속성이 변경 될 때 재 컴파일 감소 : 소비자를 재 컴파일 할 필요가 없음
  • 깔끔한 퍼블리싱 : 새로운 maven-publish 플러그인과 함께 사용하면 Java 라이브러리는 라이브러리에 대해 컴파일하는 데 필요한 것과 런타임에 라이브러리를 사용해야하는 것 (즉, 라이브러리 자체를 컴파일하는 데 필요한 것과 라이브러리에 대해 컴파일하는 데 필요한 것을 혼합하십시오.

컴파일 구성은 여전히 ​​존재하지만 apiimplementation구성이 제공 하는 보장을 제공하지 않으므로 사용해서는 안됩니다 .


참고 : 앱 모듈에서 라이브러리 만 사용하는 경우 (일반적인 경우) 아무런 차이가 없습니다.
서로 다른 모듈을 가진 복잡한 프로젝트가 있거나 라이브러리를 만드는 경우에만 차이점을 볼 수 있습니다.


답변

이 답변의 차이를 설명 할 것이다 implementation, api그리고 compile프로젝트에.


세 개의 Gradle 모듈이있는 프로젝트가 있다고 가정 해 보겠습니다.

  • 앱 (Android 애플리케이션)
  • myandroidlibrary (Android 라이브러리)
  • myjavalibrary (Java 라이브러리)

appmyandroidlibrary종속한다. myandroidlibrarymyjavalibrary 종속한다.

의존성 1

myjavalibraryMySecret클래스를

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());

이제 의존성에 대해 이야기 해 봅시다 …

app:myandroidlibrary그래서 appbuild.gradle 사용 에서 소비해야합니다 implementation.

( 참고 : API / 컴파일도 사용할 수 있습니다. 그러나 잠시 동안 그 생각을 유지하십시오.)

dependencies {
    implementation project(':myandroidlibrary')
}

의존성 2

myandroidlibrarybuild.gradle은 어떻게 생겼을까 요? 어떤 범위를 사용해야합니까?

우리는 세 가지 옵션이 있습니다 :

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

의존성 3

그들 사이의 차이점은 무엇이며 어떻게 사용해야합니까?

컴파일 또는 API (옵션 # 2 또는 # 3)
의존성 4

당신이 사용하는 경우 compileapi. Android 애플리케이션은 이제 클래스 인 myandroidcomponent종속성 에 액세스 할 수 있습니다 MySecret.

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

구현 (옵션 # 1)

의존성 5

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

어떤 구성을 선택해야합니까? 그것은 실제로 귀하의 요구 사항에 달려 있습니다.

당신이 경우 종속성 노출 할 사용 api하거나 compile.

당신이 경우 종속성을 노출하지 않으려는 (내부 모듈 숨어을)를 사용합니다 implementation.

노트 :

이것은 Gradle 구성의 요지 일뿐입니다 ( 표 49.1 참조) . Java 라이브러리 플러그인- 자세한 설명을 위해 종속성을 선언하는 데 사용되는 구성

이 답변의 샘플 프로젝트는 https://github.com/aldoKelvianto/ImplementationVsCompile에서 제공됩니다.


답변

Compile구성이 더 이상 사용되지 않으므로 implementation또는 로 대체해야합니다 api.

https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation 에서 문서를 읽을 수 있습니다 .

간단한 부분은

표준 Java 플러그인과 Java 라이브러리 플러그인의 주요 차이점은 후자가 소비자에게 노출되는 API 개념을 도입한다는 것입니다. 라이브러리는 다른 구성 요소에서 사용하기위한 Java 구성 요소입니다. 다중 프로젝트 빌드에서 매우 일반적인 유스 케이스이지만 외부 종속성이있는 즉시.

플러그인은 의존성을 선언하는 데 사용할 수있는 api와 구현의 두 가지 구성을 제공합니다. API 구성은 라이브러리 API에서 내 보낸 종속성을 선언하는 데 사용해야하는 반면 구현 구성은 구성 요소 내부의 종속성을 선언하는 데 사용해야합니다.

자세한 설명은이 이미지를 참조하십시오.
간단한 설명


답변

간단한 해결책 :

더 나은 방법은 모든 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에게 명시 적으로 모듈을 다시 컴파일하도록 지시 할 수 있습니다.

제론 몰 블로그


답변

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


답변

평신도 용어의 간단한 차이점은 다음과 같습니다.

  • 명시된 종속성의 멤버를 노출시켜 다른 모듈을 지원하는 인터페이스 또는 모듈에서 작업중인 경우 ‘api’를 사용해야합니다.
  • 명시된 종속성을 내부적으로 구현하거나 사용할 애플리케이션 또는 모듈을 작성하는 경우 ‘구현’을 사용하십시오.
  • ‘compile’은 ‘api’와 동일하게 작동하지만 라이브러리를 구현하거나 사용하는 경우 ‘implementation’이 더 잘 작동하고 리소스를 절약 할 수 있습니다.

포괄적 인 예를 보려면 @aldok의 답변을 읽으십시오.


답변

버전부터 5.6.3 Gradle을 문서는 오래된 여부를 확인하는 엄지 손가락의 간단한 규칙을 제공 compile의존성 (또는 새가)를 교체해야 implementation하거나 api의존성 :

  • 가능 하면 implementation구성보다 선호api

이것은 소비자의 컴파일 클래스 경로의 의존성을 유지합니다. 또한 구현 유형이 실수로 공개 API로 누출되는 경우 소비자는 즉시 컴파일에 실패합니다.

언제 api구성 을 사용해야 합니까? API 종속성은 라이브러리 이진 인터페이스에 노출되는 유형을 하나 이상 포함하는 것으로 ABI (Application Binary Interface)라고도합니다. 여기에는 다음이 포함되지만 이에 국한되지는 않습니다.

  • 수퍼 클래스 또는 인터페이스에 사용되는 유형
  • 일반 매개 변수 유형을 포함하여 공용 메소드 매개 변수에 사용되는 유형 (공개는 컴파일러에서 볼 수있는 것입니다. 즉, Java 세계에서 공개, 보호 및 패키지 개인 구성원
  • 공공 장소에서 사용되는 유형
  • 공개 주석 유형

반대로 다음 목록에 사용 된 모든 유형은 ABI와 관련이 없으므로 implementation종속성 으로 선언해야합니다 .

  • 메소드 본문에 독점적으로 사용되는 유형
  • 개인 회원에게 독점적으로 사용되는 유형
  • 내부 클래스에서 독점적으로 발견되는 유형 (향후 버전의 Gradle을 사용하면 공개 API에 속하는 패키지를 선언 할 수 있습니다)