[ScratchRevealCard] 1. 라이브러리 개발할 때 의존성 세팅방법 (implementation vs api)

2025. 5. 15. 14:31·라이브러리 개발일기

저는 오늘부터 라이브러리 개발을 해볼겁니다.

저는 그저 안드로이드 개발을 좋아하는 작은 취준생일 뿐이고 라이브러리 개발을 한 번도 해보지 않았습니다.

따라서 이 시리즈는 당분간 머리박치기를 하면서 라이브러리를 만들어가는 날것의 과정을 담을 것입니다. (정제되고 깔끔한 컨텐츠는 기대하지 마시길 바랍니다.)

 

왜 라이브러리 개발을 하게 되었냐면 ... ! 사실 대학시절, 취준하면서 팀프로젝트도 여러개 했고 개인프로젝트도 몇개 했었는데 전부다 앱개발이었습니다. 근데 이 앱을 만든다는게요 생각보다 볼륨이 큰 작업이라고 느껴지거든요? 아이디어 기획부터 해야하고 디자인, 기능명세, 협업관리 이것저것 신경써야 하는게 너~~~무 많습니다. 나는 개발만 하고싶은데 ...

 

마침 최근에 진행했던 팀 프로젝트가 얼추 마무리 되기도 했고, 힘들었던 저는 '개인프로젝트나 다시 해보자' 라고 생각을 하던 참이었는데, 또 아이디어 짜내려니 너무 힘든거 있잖아요? 그래서 갑자기 라이브러리나 만들어볼까? 하는 생각이 들었습니다. 

앱서비스처럼 거대한 아이디어나 기획이 필요없이 작은 기능하나만 기획해서 순수 개발에 몰입할 수 있는, 그리고 한번도 안해본 도전의 영역이라는 도파민 터지는 생각을 해버린 것입니다. 라이브러리 개발이라니 너무 멋지잖아요!!!!!!

 

 

그래서 ScratchRevealCard 란?

이름 그대로 긁어서 어떠한 컨텐츠가 드러나는 카드뷰 같은것을 만들것입니다.

그 왜 복권 있잖아요 동전으로 긁으면 복권 번호 나오는 부분, 그걸 만들거에요. 안드로이드에서 UI컴포넌트나 이미지위에 미리보기 방지 테이프를 붙이고, 이를 손가락으로 긁으면 내용이 드러나는 UI 컴포넌트를 개발해서 라이브러리화 시킬겁니다.

 

기획 의도

위 설명만 들으면 아마 고작 이딴게 라이브러리? 라는 생각이 들 수 도 있다고 생각해요.

 

원래는 이전에 팀프로젝트를 할 때 BottomSheet으로 애를 상당히 먹어서 Compose에서 커스텀이 자유로운 BottomSheet 컴포넌트를 만들고 싶었습니다. 아무래도 Scaffold에 종속되어 있는 BottomSheet을 커스텀하려 했더니 중첩스크롤과 같은 기능들이 제대로 동작하지 않았고 실제로 버그로 이슈화 되기도 했거든요.

 

따라서 BottomSheet 자체에만 집중하여 다양한 기능을 제공하고 최적화된 컴포넌트를 라이브러리화 함으로써 프로젝트당시 느꼈던 불편함을 해소하게 되는 그런 스토리의 방향으로 처음에 기획을 했습니다...

그런데 사실 자신이 없었어요 ... 'AOSP에서도 아직 해결되지 않은 UI 컴포넌트 문제를 라이브러리 개발을 한 번도 해보지 않은 내가 좋은 퀄리티로 해결할 수 있을까?' 와 같은 생각 때문에 난이도를 조금 낮추게 되었습니다 ㅎㅎ

 

일단 간단한 기능을 가진 라이브러리를 하나 만들어보고, 프로젝트구성은 어떻게 해야 하는지, 일반 앱을 개발하는것과 어떤점이 다른지, 라이브러리로써 배포과정은 어떻게 되는지 와 같은것들을 전반적으로 파악 하는것이 이번 ScratchRevealCard의 목표입니다!

 

옆집 훔쳐보기

음식점 창업을 하려고 한다면 가장먼저 뭐부터 해야할까요? 그건 바로 이미 장사가 잘되는 유사업종, 맛집들을 탐사해보고 실제로 어떻게 장사를 하고있고 저집은 왜 장사가 잘 되는지 파악을 해야 할 것입니다.

 

저도 라이브러리를 제작할 거기 때문에 이미 구면인 Glide 라이브러리를 훔쳐보았습니다.

 

(여담)

https://github.com/bumptech/glide/pull/5447

 

Fix ResourceID validation check expression by hyuns66 · Pull Request #5447 · bumptech/glide

Description related issue : #5404 I changed three methods which have wrong expression getFallbackDrawable() getErrorDrawable() getPlaceholderDrawable() Resource IDs can be negative, but the func...

github.com

제가 해결한 Glide 이슈 인데 담당 컨트리뷰터랑 대화나눠서 승인까지 받았지만, 머지할때 뭐 잘못눌러서 머지 실패한 후로 승인을 못받고 있네요 ㅠㅠ 아무리 불러도 대답이 없어... 승인해줘 kanelbulle!!!!

 

프로젝트 구성부터 훔쳐보자

 

Glide 라이브러리의 프로젝트 구조는 전체적으로 이런 형태를 띄고 있습니다

개발력의 한계로 인해 모든코드를 다 뜯어보진 못했지만 그래도 하나하나 들어가서 훑어본 바로는 여러가지 역할을 하는 모듈을 분리한 멀티모듈 프로젝트임을 알 수 있었습니다.

 

  • samples 모듈의 경우 glide 를 활용할 수 있는 샘플 프로젝트가 들어가 있었습니다. uri나 svg, giphy 등을 활용하여 이미지를 띄우는 앱 예제가 들어가 있었고, 익숙한 액티비티, 프래그먼트 형식의 프로젝트 였습니다.
  • benchmark, testutil 같은 모듈의 경우 여러 환경에서의 테스트코드와 이에 필요한 테스트 모듈이 작성되어 있었습니다.
  • library 모듈이 가장 핵심이 되는 glide 관련 모든 라이브러리 로직과 매서드가 구현되어 있는 모듈이었습니다.
  • 이외에도 어노테이션을 생성하기 위해 어노테이션 프로세서를 작성한 annotation 모듈과, 타 서드파티 라이브러리와의 통합을 제공하기 위한 모듈들도 존재했습니다.

 

따라서 저는 샘플 앱과 라이브러리 모듈 두 개의 모듈로 구성된 매우 간단한 멀티모듈 라이브러리 프로젝트를 개발하려고 합니다.

 

라이브러리 모듈 구현은 어떻게?

 

라이브러리 모듈은 이런식으로 구성이 되어 있습니다.

액티비티나 프래그먼트같은 안드로이드 컴포넌트는 존재하지 않으며 순수 자바 인터페이스와 구현체 등으로 구성되어 있습니다. 

그럼에도 불구하고 이미지를 로드하기 위해서는 Context와 같은 안드로이드 종속성이 필요하고, 매서드 내에서도 이를 활용해야 하기 때문에 안드로이드 종속성이 들어가 있다는 점이 특이하다고 느꼈습니다.

 

왜냐하면 이 라이브러리를 사용하는 유저 프로젝트에서 사용하는 안드로이드 라이브러리 버전과, Glide의 종속성에 선언되어 있는 안드로이드 라이브러리 버전이 충돌되면 어떻게 되는건지가 궁금해졌기 때문입니다.

 

그 부분은 공식문서에서 설명을 찾아볼 수 있었습니다.

 

그림에서 알 수 있듯 유저 앱에서 A와 B 두 개의 라이브러리가 동일한 라이브러리 C에 대한 의존성을 모두 가지고 있는 경우 높은 버전의 라이브로리로 자동승격 된다고 합니다.

 

유저 프로젝트에 직접 속한 의존성과 충돌할 경우 역시 마찬가지로 최신 버전으로 자동 승격되게 됩니다.

 

gradle 구성

dependencies {
    api project(':third_party:gif_decoder')
    api project(':third_party:disklrucache')
    api project(':annotation')
    api libs.androidx.fragment
    api libs.androidx.vectordrawable
    api libs.androidx.exifinterface
    api libs.androidx.tracing
    compileOnly libs.androidx.appcompat

    if (project.plugins.hasPlugin('net.ltgt.errorprone')) {
        errorprone libs.errorprone.core
    }

    testImplementation libs.androidx.appcompat
    testImplementation project(':testutil')
    testImplementation libs.guava.testlib
    testImplementation libs.truth
    testImplementation libs.junit
    testImplementation libs.mockito
    testImplementation libs.robolectric
    testImplementation libs.mockwebserver
    testImplementation libs.androidx.test.core
    testImplementation libs.androidx.junit
    testImplementation libs.androidx.test.runner
}

 

Glide 의 library 패키지에 있는 build.gradle 파일을 보면 위와 같이 의존성이 추가되어 있음을 알 수 있습니다.

보통 프로젝트에서 build.gradle을 다룰 때 implementation을 사용했는데, 라이브러리에서는 api라는 키워드를 통해 의존성을 선언하고 있는 것을 발견했습니다.

 

공식문서에 의하면 gradle을 통해 의존성을 선언하기 위해서는 여러가지 방법이 존재합니다.

키워드 내 소스코드가
빌드될 때 포함
배포 AAR 에 포함 다른모듈로 종속항목 이전 대표적 사용 용도
api O O O 함수 파라미터·리턴·상속 등 퍼블릭 API에 드러나는 타입, 런타임에 꼭 필요한 라이브러리
implementation O O X 내부 구현만 쓰는 라이브러리 (로깅, JSON 파서 등) – 소비자에게 숨겨 충돌·APK 크기 최소화
compileOnly O X X 빌드 타임 참고용 선택 기능 (애노테이션, AppCompat 확장). 런타임·APK에 포함 안 됨
testImplementation 테스트 코드만 O 테스트 실행 시만 O X JUnit, Mockito, Robolectric 같은 테스트 전용 라이브러리

 

주목해야 할 것은 implementation과 api의 차이점 입니다.

이 둘은 거의 비슷하게 동작하지만 api의 경우 본인을 사용하는 외부 모듈로 의존성이 전파된다는 특징이 있습니다. 따라서 평소 모놀리식 구조로 앱개발을 할 때에는 자체 패키지로만 앱을 개발했기 때문에 implementation만 사용해서 의존성을 선언해주어도 문제가 되지 않았습니다. 그러나 멀티모듈이나 라이브러리 모듈같은 경우 다른 앱 모듈에서 활용할 것을 생각하여 필요한 의존성들을 적절히 api 키워드로 선언해주어야 의존성 문제가 생기지 않는 다는 점을 인지하고 개발해야 합니다.

 

implementation과 api를 언제 사용해야할지 장단점을 정리해보면 다음과 같습니다

 

implementation 장단점

의존성 선언의 범위가 현재모듈로 제한되므로 빌드속도가 빠르고 버전간 충돌가능성이 낮으며 충돌이슈가 발생했어도 해결이 쉽습니다.

그러나 타 모듈과 함께 사용하는 경우에 implementation을 쓴다면 각 모듈에 일일이 직접 의존성을 추가해줘야 하는 번거로움이 있습니다.

사실상 의존성 선언에 있어서 가장 안전한 방식이며 이렇다할 단점이 크게 없으므로 대부분의 상황에선 implementation을 쓰는게 좋습니다.

 

api 장단점

타 모듈에 의존성이 전파되므로 해당 모듈을 소비하고 있는 모듈에 자동병합되는 장점이 있습니다. 그러나 의존성 선언의 범위가 여러 모듈에 걸쳐지기 때문에 의존성에 변경점이 생겼을 때 상위 모듈까지 모두 빌드해야 하므로 빌드속도가 느려지고 의존성 충돌이슈를 해결하기 복잡하다는 단점이 존재합니다.

따라서 api 키워드는 꼭 필요한 의존성에 대해서만 조심스럽게 선언해주어야 제대로 활용할 수 있는 키워드입니다.

 

api 키워드는 언제 쓰면 좋을까?

@Composable
fun FancyCard(
    image: Painter,                 // 1
    modifier: Modifier = Modifier,
    overlayVector: ImageVector?,    // 2
    onClick: () -> Unit = {},       // 3
) : CustomClassModule {			// 4
	// 내부 로직 구현
    	// 로직 구현에 각종 서드파티 라이브러리 활용
    	// GSON, Glide, Retrofit ...	// 5
}

 

 

 (원래 컴포저블 함수에선 return 타입을 쓰지 않지만 예제이므로 설명과 이해를 위해 달아놨습니다.)

제가 제공하는 라이브러리에서 위와 같은 Composable 컴포넌트를 제공하려고 한다 가정해봅시다.

 

1, 2, 3, 4 번의 경우 라이브러리에서 유저에게 제공하는 함수 시그니처에 포함되기 때문에 해당 라이브러리를 사용하는 사용자가 직접 유저코드에 노출시키고 import 시켜야 하는 의존성이라고 볼 수 있습니다.

그러나 내부 로직 구현에 사용하는 5 번 부분은 사용자의 유저코드에 포함되지 않으며 유저가 알 필요도 없는 부분입니다.

따라서 1, 2, 3, 4 에 해당하는 의존성은 api 로 노출하고, 5에 해당하는 의존성들은 implementation으로 의존성 선언을 하면 될 것입니다.

보통의 앱개발을 하면서 본인 프로젝트만 관리할 때에는 전부 implementation을 활용해도 큰 상관이 없지만 여러 사람들에게 제공되는 라이브러리를 개발할 때에는 말이 달라집니다.

이러한 경우 implementation으로 선언해도 되는 의존성을 api로 노출했을 때에는 큰 문제가 생기지 않으며 문제가 생겨도 해결가능한 경우가 많지만, api로 노출해야 하는 의존성을 implementation으로 선언했을 때에는 라이브러리 사용자체에 문제가 생길 가능성이 있으므로 라이브러리를 개발할 때에는 가능하면 api로 의존성을 노출하고 컴파일 최적화를 위해서 신중하게 implementation을 적절히 사용하는것이 바람직할 것 같습니다.

'라이브러리 개발일기' 카테고리의 다른 글

[ScratchRevealCard] 3. Modifier의 그래픽 수정자 - drawScope, graphicsLayer  (2) 2025.06.17
[ScratchRevealCard] 2. 그림판 구현으로 기술적 검증을 해보자.  (1) 2025.05.31
'라이브러리 개발일기' 카테고리의 다른 글
  • [ScratchRevealCard] 3. Modifier의 그래픽 수정자 - drawScope, graphicsLayer
  • [ScratchRevealCard] 2. 그림판 구현으로 기술적 검증을 해보자.
나는 커서 멋진 개발자가 될래요
나는 커서 멋진 개발자가 될래요
renovatio-dev-hyuns 님의 블로그 입니다.
다음 글
[ScratchRevealCard] 2. 그림판 구현으로 기술적 검증을 해보자.
2025.05.31
  • 나는 커서 멋진 개발자가 될래요
    Renovatio
    나는 커서 멋진 개발자가 될래요
  • 전체
    337
    오늘
    0
    어제
    0
    • 분류 전체보기 (14)
      • Pixionary 기술노트 (3)
      • 앗차 기술노트 (1)
      • 삽질일기 (1)
      • 라이브러리 개발일기 (3)
      • 작고 소듕한 깨달음 (0)
      • 시리즈 (4)
        • Android Jetpack Compose (0)
        • Hilt들고 MVVM정복 (4)
      • CS (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

    • [ScratchRevealCard] 3. Modifier의⋯
      2025.06.17
    • [ScratchRevealCard] 1. 라이브러리 개발할⋯
      2025.05.15
    • 네트워크 요청을 안전하게 해보자 (feat. Templat⋯
      2025.08.20
  • 태그

  • 최근 댓글

    • 잘 봤어요
      정보왕창
      ·08.15
    • 나는 커서 멋진 개발자가 될래요님 잘보고 갑니다. 공감꾹~
      빌게이츠야그
      ·08.15
    • 나는 커서 멋진 개발자가 될래요님 들러서 좋은 글 잘 보고⋯
      SojiReporter
      ·08.14
    • 나는 커서 멋진 개발자가 될래요님 오늘도 값진 정보 잘 얻⋯
      스마트홍홍
      ·08.14
    • 잘 봤어요
      한달동안
      ·08.14
  • 최근 글

    • 네트워크 요청을 안전하게 해보자 (feat. Templat⋯
      2025.08.20
    • [자료구조] 트라이(Trie)
      2025.08.13
    • [ScratchRevealCard] 3. Modifier의⋯
      2025.06.17
    • [ScratchRevealCard] 2. 그림판 구현으로 ⋯
      2025.05.31
    • [ScratchRevealCard] 1. 라이브러리 개발할⋯
      2025.05.15
  • hELLO· Designed By정상우.v4.10.4
나는 커서 멋진 개발자가 될래요
[ScratchRevealCard] 1. 라이브러리 개발할 때 의존성 세팅방법 (implementation vs api)
상단으로

티스토리툴바