앱을 출시하기 전 꼭 포함해야 하는 화면 중 하나가 바로 '오픈소스 라이선스' 명시입니다. 일반적으로 가장 먼저 떠올리는 방법은 Google에서 제공하는 play-services-oss-licenses-plugin 사용하는 방식이겠죠. 저도 공식 지원인 플러그인을 적용했습니다.
하지만 막상 구현하고 보니 화면이 제대로 표시되지 않았어요. 세팅하는 과정에서 뭔가 잘못했나? 싶어서 여러번 봤지만 특별하게 잘못된 부분은 없었습니다..
// app/build.gradle.kts
plugins {
id("com.google.android.gms.oss-licenses-plugin")
}
// ... dependencies
// Activity 코드
startActivity(Intent(this, OssLicensesMenuActivity::class.java))

위 코드처럼 적용했지만, 결과물은 “This app does not have any open source licenses” 라는 메세지와 EdgeToEdge가 적용되지 않은 액티비티가 호출 되었어요ㅋㅋ..
혹시나 싶어 깃허브 이슈를 뒤져보니, 저와 같은 문제를 겪는 개발자들이 이미 많이 있었어요.
https://github.com/google/play-services-plugins/issues/105
OSS Licenses - This app does not have any open source licenses · Issue #105 · google/play-services-plugins
After upgrading oss-licenses-plugin to version 0.10.0 (play-services-oss-licenses remains 17.0.0) only the message This app does not have any open source licenses is displayed in OssLicensesMenuAct...
github.com
https://github.com/google/play-services-plugins/issues/296
oss-licenses-plugin is not edge-to-edge ready · Issue #296 · google/play-services-plugins
Describe the bug Integrate the app with oss-licenses-plugin To Reproduce Steps to reproduce the behavior: Open the OssLicensesActivity Expected behavior Activity supports edge-to-edge (enforced wit...
github.com

결론적으로 현재 시점에서 Google의 공식 플러그인은 안정적인 해결책이 되기 어렵다고 판단했어요. 그래서 두가지 선택을 고민했습니다.
- 다른 라이브러리를 찾는다.
- 내가 직접구현한다.
2번의 경우는 공부가 되겠지만 리소스를 많이 써야 하는 작업이 아니라고 생각했어요. 그래서 서드파티 라이브러리를 찾아봤습니다.
AboutLibraries
서칭을 통해서 mikepenz/AboutLibraries라는 라이브러리를 발견했어요. (오픈소스 라이선스를 고지하기 위해 또 다른 오픈소스를 사용하는 상황..ㅋ)
다른 라이브러리도 있었지만 활발하게 유지보수되며 최신 Android 환경을 잘 지원하기도 했고, KMP를 지원하는걸 보고 앞으로도 꾸준히 관리 될거라고 생각이 들어서 선택했어요.
적용 과정은 아주 간단해요. 먼저 libs.versions.toml 파일에 라이브러리 정보를 추가해요.
# libs.versions.toml
[versions]
aboutLibraries = "13.0.0-rc01"
[libraries]
aboutlibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutLibraries" }
[plugins]
aboutlibraries-android = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutLibraries" }
다음으로 프로젝트 단위와 앱 단위의 build.gradle.kts에 플러그인을, 라이선스 화면을 구현할 모듈에 의존성을 추가해 줬어요.
// 프로젝트의 build.gradle.kts
plugins {
alias(libs.plugins.aboutlibraries.android) apply false
}
// app/build.gradle.kts
plugins {
alias(libs.plugins.aboutlibraries.android)
}
// 라이선스 화면이 있는 모듈의 build.gradle.kts
dependencies {
implementation(libs.aboutlibraries.compose.m3)
}
이제 UI를 구성할 차례에요. AboutLibraries가 제공하는 LibrariesContainer 컴포저블을 사용하면 아주 간단하게 사용가능해요.
@Composable
fun OssLicensesScreen(
paddingValues: PaddingValues,
onBackClick: () -> Unit
) {
val libraries by produceLibraries()
Column(
modifier = Modifier
.fillMaxSize()
.background(HilingualTheme.colors.white)
.padding(paddingValues)
) {
BackTopAppBar(
title = "오픈소스 라이선스",
onBackClicked = onBackClick
)
LibrariesContainer(
libraries = libraries,
modifier = Modifier.fillMaxSize()
)
}
}
이렇게 간단하게 적용이 끝났어요. 그런데 한 가지 궁금증이 생겼어요. '이 라이브러리는 어떻게 내부적으로 모든 의존성 정보를 가져오는 걸까?' 런타임에 Maven 저장소를 모두 검색하지는 않을 텐데..
궁금증을 해결하기 위해 AboutLibraries의 내부 동작을 분석해 봤어요. 핵심은 모든 무거운 작업을 빌드 시점에 처리해서 런타임 오버헤드를 없애는 것에 있었어요.
전체 과정은 크게 3단계로 나눌 수 있어요
- Gradle 플러그인을 통한 메타데이터 수집 (빌드 시점)
- 빌드 프로세스가 시작되면, com.mikepenz.aboutlibraries.plugin.android 플러그인이 동작해요.
- 이 플러그인은 프로젝트의 모든 모듈과 빌드 Variants(debug, release)에 걸쳐 의존성 그래프 전체를 탐색해요.
- 각 라이브러리의 Maven 저장소 pom.xml 파일을 분석해서 라이브러리 이름, 버전, 개발자 정보, 그리고 가장 중요한 라이선스 정보를 추출해요.
- 메타데이터 직렬화 및 리소스 포함 (빌드 시점)
- 1단계에서 수집한 모든 라이브러리의 메타데이터를 aboutlibraries.json이라는 단일 JSON 파일로 직렬화해요.
- 플러그인은 이 aboutlibraries.json 파일을 앱의 res/raw 디렉터리에 자동으로 포함시켜요.
- 결과적으로, 모든 의존성 정보가 APK 내부에 하나의 정적인 리소스로 패키징 됩니다.
- UI 모듈을 통한 데이터 파싱 및 렌더링 (런타임 시점)
- 사용자가 오픈소스 라이선스 화면에 진입하면, produceLibraries() 함수가 호출돼요.
- 이 함수는 R.raw.aboutlibraries 식별자를 통해 APK에 포함된 aboutlibraries.json 파일을 읽어요.
- JSON 파일의 내용을 파싱해서 Library, License와 같은 데이터 객체로 변환한 뒤, LibrariesContainer 컴포저블이 이 데이터를 받아 목록을 화면에 렌더링해요.
이러한 구조 덕분에 의존성 정보를 분석하는 복잡한 작업은 모두 빌드 시점에 끝나고, 런타임에는 단순히 앱 내부에 포함된 정적 JSON 파일을 읽어 UI에 보여주는 가벼운 작업만 수행하게 돼요. 이것이 바로 AboutLibraries가 런타임 성능 저하 없이 안정적으로 라이선스 목록을 제공할 수 있는 원리에요.
Google의 공식 오픈소스 라이선스 플러그인이 불안정하여 겪었던 문제를 AboutLibraries를 도입하며 해결할 수 있었어요.
오픈소스 생태계 덕분에 개발이 편해진 만큼, 라이선스를 명확히 고지해서 생태계에 대한 존중을 지키는 문화를 함께 만들어가면 좋겠습니다. 감사합니다 :)
'Android > Compose' 카테고리의 다른 글
| [Android Compose] 골치덩어리 EdgeToEdge를 잘 써보자. (1) | 2025.09.23 |
|---|---|
| [Android Compose] @Composable 종속성을 StateFlow로 바꿔보자 (0) | 2025.08.09 |
| [Android Compose] flowWithLifecycle은 언제 쓰면 좋을까? (0) | 2025.08.08 |
| [Android Compose] Effect Handlers 딥다이브 (0) | 2025.06.20 |
| [Android Compose] 상태 읽기 지연(Defer State Reads)으로 리컴포지션 최적화하기 (0) | 2025.06.18 |