Gradle 구현 및 API 구성


231

종속성을 구축하는 동안 구성 apiimplementation구성 의 차이점이 무엇인지 파악하려고합니다 .
문서에서 implementation더 나은 빌드 시간이 있다고 말하지만 비슷한 질문 에서이 의견 을 보는 것이 사실인지 궁금합니다.
나는 gradle의 전문가가 아니기 때문에 누군가 도울 수 있기를 바랍니다. 설명서를 이미 읽었 지만 이해하기 쉬운 설명이 궁금합니다.


1
당신은 여기 를 읽었 습니까?
MatPag

사실, 나는 그랬지만, 내가 말했듯이 그 의견은 그것에 대해 궁금해했다. 그래서 지금 좀 길을 잃었
reinaldomoreira

라이브러리 종속성을에서 compile로 전환 할 것입니다 api. 내부적으로 사용하는 라이브러리는 최종 라이브러리에 노출되지 않은 일부 개인 구현을 사용할 수 있으므로 투명합니다. 이러한 "내부-사적"종속성을 전환 할 수 있으며 implementationAndroid gradle 플러그인이 앱을 컴파일 할 때 해당 종속성의 컴파일을 건너 뛰고 빌드 시간이 줄어 듭니다 (그러나 런타임에 이러한 종속성을 사용할 수 있음). 로컬 모듈 라이브러리가있는 경우에도 동일한 작업을 수행 할 수 있습니다.
MatPag

1
여기에 'API'와 '구현'의 짧은 그래픽 설명입니다 : jeroenmols.com/blog/2017/06/14/androidstudio3는
버트 C 브라운

1
그 멋진 게시물입니다! 감사합니다 @albertbraun
reinaldomoreira

답변:


418

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.gradle사용 한다고 가정하십시오 .apidependencies{}

dependencies {
    api project(':InternalLibrary')
}

MyLibrary코드에서 사용하려면 앱에서 build.gradle다음과 같은 종속성을 추가하십시오.

dependencies {
    implementation project(':MyLibrary')
}

은 Using api구성 (또는 사용되지 않는 compile당신은에 액세스 할 수 있습니다) InternalLibrary응용 프로그램 코드에서 :

// Access 'MyLibrary' (granted)
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대신 apiMyLibrary:

dependencies {
    implementation project(':InternalLibrary')
}

InternalLibrary.giveMeAString()더 이상 앱 코드 를 호출 할 수 없습니다.

권투 전략 이런 종류의 안드로이드 Gradle을가에서 당신이 편집 뭔가 경우 알고 플러그인 할 수 있습니다 InternalLibrary, 그것은 단지의 재 컴파일 트리거해야 MyLibrary하고 하지 액세스 권한이 없기 때문에, 전체 응용 프로그램의 재 컴파일 InternalLibrary.

중첩 된 종속성이 많을 경우이 메커니즘으로 빌드 속도를 크게 높일 수 있습니다. (이것에 대한 완전한 이해를 위해 마지막에 링크 된 비디오를보십시오)

결론

  • 당신이 3.XX 플러그인 새로운 안드로이드 Gradle을로 전환하면 모든 교체해야 compileimplementation키워드 (* 1) . 그런 다음 앱을 컴파일하고 테스트하십시오. 모든 것이 괜찮다면 코드를 그대로 두십시오. 문제가 발생하면 종속성에 문제가 있거나 현재 비공개적이고 더 접근하기 어려운 것을 사용했습니다. 안드로이드 Gradle 플러그인 엔지니어 Jerome Dochez의 제안 (1 ) * )

  • 라이브러리 관리자 인 경우 라이브러리 api의 공용 API에 필요한 모든 종속성에 사용해야 implementation하지만 최종 사용자가 사용해서는 안되는 테스트 종속성 또는 종속성에 사용해야합니다.

유용한 기사 구현API 의 차이점을 보여주는

참조 (시간 절약을 위해 분할 된 동일한 비디오)

Google I / O 2017-Gradle 빌드 속도 향상 (전체 비디오)

Google I / O 2017-Gradle 빌드 속도 향상 (새로운 GRADELE PLUGIN 3.0.0 PART ONLY)

Google I / O 2017-Gradle 빌드 속도 향상 ( 1 * 참조 )

안드로이드 문서


4
라이브러리 모듈에서 API가 제대로 작동하지 않는 것으로 나타났습니다. 그것을 사용하면 여전히 앱 프로젝트의 종속성에 액세스 할 수 없습니다. 해당 라이브러리 자체의 코드에만 액세스 할 수 있습니다.
앨런여

1
이것은 양호하며 디버그 빌드에서는 작동하지만 ProGuard (릴리스 버전)에서 MyLibrary#myString()ProGuard를 InternalLibrary제거 하면 충돌이 발생 합니다. ProGuard의 앱에서 android-libs를 사용하는 가장 좋은 방법은 무엇입니까?
hardysim

3
대답이 정확하지 않다고 생각하면 응용 프로그램은 MyLibrary에 원하는 범위를 사용할 수 있습니다. MyLibrary가 API / 구현을 사용하는지 여부에 따라 InternalLibrary를 보거나 보지 않을 것입니다.
Snicolas

2
고마워요 안드로이드의 공식 문서에 제공된 것보다 훨씬 더 멋진 설명
Henry

2
그것은 아름다운 설명입니다. 이론과 콘크리트가 훌륭하게 혼합되었습니다. 잘 했어. 감사합니다
Peter Kahn

134

나는 생각하고 싶다 api 의존성을 비공개 (다른 모듈에서 본) implementation의존성을 비공개 (이 모듈에서만 볼 수 있음)로 생각합니다.

달리 유의, public/ private변수 및 방법 api/ implementation종속성 런타임에 의해 수행되지 않는다. 이는 단지 빌드 타임 최적화 일 뿐이며 Gradle, 종속성 중 하나가 API를 변경할 때 다시 컴파일해야하는 모듈을 알 수 있습니다 .


16
이 답변의 단순함을 좋아합니다. 대단히 감사합니다.
Kevin Gilles

2
실제 차이점 (AFAICT)은 생성 된 pom 파일이 api종속성을 "컴파일"범위 (라이브러리의 종속성 및 라이브러리에 의존하는 모든 항목으로 포함됨)와 implementation"런타임"범위의 종속성 (더 나은쪽에 있음) 코드가 실행될 때 클래스 경로이지만 라이브러리를 사용하는 다른 코드를 컴파일 할 필요는 없습니다).
Shadow Man

@ShadowMan POM 파일 생성, Gradle 범위를 Maven 범위에 매핑하는 방법을 담당하는 플러그인의 구현 세부 사항입니다 .
dev.bmax

1
당신은 사용해야 implementation실행하는 데 필요한 (그리고 컴파일하려면 라이브러리에 대한) 임의의 의존성을 위해,하지만이 자동적으로 라이브러리를 사용하는 프로젝트에 들어갔습니다 할 수 없습니다. 예를 들어 jax-rs, 라이브러리는 RESTeasy를 사용할 수 있지만 Jersey를 대신 사용하려는 라이브러리를 사용하는 프로젝트로 해당 라이브러리를 가져 와서는 안됩니다.
Shadow Man

1
간단하고 명확한 대답을 D 감사 : 이것은 당신이 사람이 그 물건을 얻는 방법을 알고있다
엘리아스 Fazel

12

라이브러리로 사용 하고 라이브러리로 사용 하는 app모듈이 있다고 가정하십시오 . 이 같은:lib1lib1lib2app -> lib1 -> lib2 .

이제 api lib2in을 사용 lib1하면 다음을 app 사용할 lib2api lib1또는 모듈 implementation lib1에서 코드 를 볼 수 있습니다app .

사용 때 implementation lib2lib1, 그 다음 app 볼 수lib2 코드를.


5

@matpag@ dev-bmax의 답변은 사람들이 구현과 API 간의 다른 사용법을 이해할 수 있도록 충분히 분명합니다. 나는 다른 각도에서 추가 설명을하고 싶습니다. 같은 질문을하는 사람들을 돕기를 바랍니다.

테스트를 위해 두 가지 프로젝트를 만들었습니다.

  • 'frameworks-web-gradle-plugin'이라는 Java 라이브러리 프로젝트로서의 프로젝트 A 는 'org.springframework.boot : spring-boot-gradle-plugin : 1.5.20.RELEASE'에 따라 다릅니다.
  • 프로젝트 B 는 구현에 의해 프로젝트 A에 의존합니다. 'com.example.frameworks.gradle : frameworks-web-gradle-plugin : 0.0.1-SNAPSHOT'

위에서 설명한 종속성 계층 구조는 다음과 같습니다.

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

그런 다음 다음 시나리오를 테스트했습니다.

  1. 프로젝트 A를 구현에 의해 'org.springframework.boot : spring-boot-gradle-plugin : 1.5.20.RELEASE'에 의존하게하십시오 .

    gradle dependenciespoject B root dir의 터미널에서 명령을 실행하십시오. 출력의 스크린 샷과 함께 'spring-boot-gradle-plugin'이 runtimeClasspath 종속성 트리에 나타나지만 compileClasspath에는 나타나지 않는다는 것을 알 수 있습니다. 구현을 사용하여 선언 한 라이브러리를 사용하면 컴파일을 거치지 않습니다.

    여기에 이미지 설명을 입력하십시오

  2. 만들기 프로젝트 A가에 따라 달라집니다 'org.springframework.boot : 봄 - 부팅 Gradle을-플러그인 : 1.5.20.RELEASE을'에 의해 API

    실행 gradle dependencies다시 poject의 B 루트 디렉토리에있는 터미널에서 명령을. 이제 'spring-boot-gradle-plugin'이 compileClasspath 및 runtimeClasspath 종속성 트리에 모두 나타납니다.

    여기에 이미지 설명을 입력하십시오

내가 주목 한 중요한 차이점은 구현 방식으로 선언 된 생산자 / 라이브러리 프로젝트의 종속성이 소비자 프로젝트의 compileClasspath에 나타나지 않으므로 소비자 프로젝트에서 해당 lib를 사용할 수 없다는 것입니다.


2

에서 Gradle을 문서 :

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 클래스와 공용 인터페이스를 노출합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.