Implementation VS Api in Android Gradle Plugin - 번역

최초 작성일 : 2017-08-28 17:23:49
최종 수정 : 2017-11-29

글에 앞서

안녕하세요?
룩핀에서 안드로이드 개발을 하고 있는 오경식 이라고 합니다.
이 글은 인도 벵갈루루의 Bedanta Bikash Borah님이 Medium에 올린 Implementation Vs Api in Android Gradle plugin 라는 글을 번역해서 만들었습니다.
번역하면서 읽으시는 분들이 편하게 느끼기 위해 원글과 아주 약간의 어투 및 기타 차이가 있을 수 있습니다.
번역을 흔쾌히 허락해주신 Bedanta Bikash Borah님께 감사하다는 말씀 드립니다.
또한 번역이 미흡해 번역의 질이 낮게 느껴질 수 있을텐데 많은 조언 부탁드립니다.
부족한 번역 글 읽어주셔서 감사합니다.
승낙

Implementation Vs Api in Android Gradle plugin 3.0

나는 프로젝트에서 Android Gradle 플러그인 3.0을 사용하는 동안 compile 키워드가 Deprecated 되었고 새롭게 나온 implementationapi를 위해 더 이상 compile이 추후에 사용되지 않는 것으로 되었습니다.
위 두 가지 모두 예제를 통해 이해 해 보도록 하겠습니다.

샘플 어플(kotlin)은 여기있습니다.

라이브러리 모듈이 4개인 프로젝트를 가정 해 보겠습니다.

  • LibraryA

  • LibraryB

  • LibraryC

  • LibraryD

종속성(의존성) 트리는 다음과 같습니다.

모든 라이브러리 모듈 속에는 간단하게 작성 된 클래스 파일이 들어 있습니다.

LibraryD:

1
2
3
4
5
class ClassD {
fun tellMeAJoke(): String {
return "You are funny :D"
}
}

LibraryC:

1
2
3
4
5
class ClassC {
fun tellMeAJoke(): String {
return "You are funny :C"
}
}

LibraryB:

1
2
3
4
5
6
7
class ClassB {
val b = ClassD()
fun whereIsMyJoke(): String {
return b.tellMeAJoke()
}
}

LibraryA:

1
2
3
4
5
6
7
class ClassA {
val c = ClassC()
fun whereIsMyJoke(): String {
return c.tellMeAJoke()
}
}

위의 클래스 파일에서 LibraryALibraryB는 각각 LibraryC 그리고 LibraryD에 종속된다는 것을 알 수 있습니다.

LibraryA -> LibraryC

LibraryB -> LibraryD

따라서 build.gradle 파일에 이러한 종속성을 추가 해줘야 합니다.

Compile (2.0) or Api (3.0):

새로운 api 키워드는 이전 compile 키워드와 정확히 동일 합니다.
따라서 모든 compileapi로 바꿔도 제대로 동작합니다.
이제 LibraryB에서 api 키워드를 사용하여 LibraryD의 의존성을 추가해 보겠습니다.

1
2
3
4
dependencies {
. . . .
api project(path: ':librayD')
}

마찬가지로 LibraryB 가 App module에 추가 됩니다.

1
2
3
4
dependencies {
. . . .
api project(path: ':libraryB')
}

이제는 LibraryBLibraryD 모두 App module에서 접근 할 수 있습니다.
sample App에서 두 라이브러리는 다음과 같이 접근 할 수 있습니다.

Implementation (3.0):

implementationapi와 다른 점을 찾아야 할 시간입니다.
에제로 돌아가서 이번에는 implementation키워드를 이용해서 LibraryCLibraryA로 가져와 봅시다.

1
2
3
4
dependencies {
. . . .
implementation project(path: ':libraryC')
}

App module도 똑같이

1
2
3
4
dependencies {
. . . .
implementation project(path: ':libraryA')
}

이제 App module에서 LibraryC에 접근하려고 시도하면 Android Studio에서 오류가 발생합니다.

이는 우리가 api 대신 implementation을 사용한다면 App module에서 LibraryC에 직접 접근 할 수 없다는 것을 의미합니다.
그래서 implementation을 사용함으로써 이득은 무엇일까요?

Implementation vs api:

첫 번째 시나리오에서 LibraryDapi를 사용하여 컴파일 됩니다.
LibraryD 내부에서 변경이 되면, Gradle은 LibraryD, LibraryBLibraryB를 import하는 다른 모든 모듈(Module X)을 재 컴파일 해야 합니다.

첫번째 시나리오

그러나 두 번째 시나리오에서 LibraryC가 내부적으로 변경이 되면 Gradle은 LibraryCLibraryA만 다시 컴파일 하면 됩니다.
App module 에서는 LibraryC를 직접 가져오지 못하고 또한 다른 클래스들은 LibraryC안에 구현 된 것들을 직접 사용 할 수 없으니까요.

두번째 시나리오

모듈을 많이 사용하는 프로젝트에서 작업하는 경우 (이 Fragmented Podcast 에서 어마무시한 빌드 시간 관련 이야기를 들었다)이 방법을 사용하면 빌드 프로세스의 속도가 크게 빨라질 수 있습니다.
샘플 프로젝트에서 이 작업을 시도했지만 약간의 개선이 있었습니다.
다음은 모든 시나리오에 대한 빌드 보고서 입니다.

Full Build:

Full Build

Change in LibraryD:

Change in LibraryD

Change in LibraryC:

Change in LibraryC

api 와 implementation에 대한 요약 설명

api는 의존성에 추가하는 모듈이 의존하고 있는 다른 모듈 까지 접근이 가능합니다.
예 ) ModuleX 에서 LibraryA 를 api project(path: ':LibrayA')로 의존성에 추가하면 ModuleX에서 LibraryC 클래스를 접근 할 수 있습니다.

implementation는 의존성에 추가하는 모듈 외 추가하는 모듈이 의존하는 다른 모듈에는 접근이 불가능 합니다. 즉 위에 상황을 보자면 implementation project(path: ':LibraryA')로 의존성에 추가하면 ModuleX에서 LibraryC 클래스에는 접근할 수 없습니다.

위에서 보았듯이 이로 인한 차이가 발생하여 빌드 속도의 개선이 있을 수 있습니다.
다시 한번 미흡한 글 읽어주셔서 감사합니다.

TL;DR(Too Long; Didn’t Read.):

모든 compileimplementation으로 바꾸고 프로젝트를 빌드해보세요.
만일 여러분이 성공적으로 잘 된다면 훌륭한 프로젝트 입니다.
그렇지 않으면 종속성이 있는지 찾아보고 api키워드를 사용하여 해당 라이브러리를 사용합시다.