Android 빌드가 설정 단계에서 죽었다. 메시지는 이랬다.
java.lang.NoClassDefFoundError: com/android/build/gradle/BaseExtension
BaseExtension 은 오래된 AGP API 다. 그래서 자연스럽게 이렇게 읽었다 —
"AGP 가 이 클래스를 지웠고, 누군가 아직 참조하고 있다."
이 해석이 틀렸고, 여기서 세 사이클을 날렸다.
틀린 가정 위에서 한 일들
| 시도 | 결과 |
|---|---|
| AGP 버전 교체 (8.7.3 / 8.13.2 / 9.3.2) | 전부 동일하게 실패 |
| Room · KSP · KAPT 제거 | 동일 |
| 빌드 스크립트의 레거시 DSL 제거 | 동일 |
세 번 다 "누가 그 클래스를 참조하나"를 찾는 일이었다. 가정 자체를 의심하지 않았다.
가정을 확인하는 데 걸린 시간: 10초
unzip -l gradle-8.13.2.jar | grep BaseExtension
31143 com/android/build/gradle/BaseExtension.class
클래스는 있었다. AGP 9.3.2 에도 있었다. 제거된 적이 없다.
NoClassDefFoundError 는 "클래스가 없다"가 아니라
"이 클래스로더에서 안 보인다" 는 뜻이다. 둘은 다르다.
진짜 원인
Gradle 은 플러그인을 프로젝트별 클래스로더 스코프에 올린다.
- 루트
build.gradle.kts가 Kotlin 플러그인을 선언 → 루트 스코프 :android:app의plugins {}가 AGP 를 선언 → 자식 스코프
부모 클래스로더는 자식을 볼 수 없다. Kotlin 플러그인이 AGP 클래스를 찾을 방법이 없었다.
어떤 AGP 버전으로 바꿔도 안 고쳐진 이유가 이것이다. 애초에 버전 문제가 아니었다.
고친 방법
두 플러그인을 같은 스코프에 올린다.
// 루트 build.gradle.kts
plugins {
kotlin("multiplatform") version "2.4.10" apply false
id("com.android.application") version "8.13.2" apply false // 추가
kotlin("android") version "2.4.10" apply false // 추가
kotlin("plugin.compose") version "2.4.10" apply false // 추가
}
곁가지: 그럴듯한 오답
같은 증상을 본 다른 사람이 스택트레이스의 검사 이름
(AgpWithBuiltInKotlinAppliedCheck)을 보고 이렇게 결론지었다.
최신 AGP 는 Kotlin 이 내장돼 있으니
kotlin("android")를 제거하라.
이름만 보면 설득력이 있다. 실제로 해 보니 틀렸다.
Line 46: kotlin { ^ Unresolved reference
Line 47: jvmToolchain(17) ^ Unresolved reference: jvmToolchain
Kotlin 확장 자체가 사라진다. AGP jar 가 등록하는 플러그인 목록을 확인해 못을 박았다 —
Kotlin 관련은 com.android.kotlin.multiplatform.library 하나뿐이고,
이건 KMP 라이브러리 모듈용이지 앱 모듈의 kotlin("android") 대체재가 아니다.
남는 교훈
가정을 고치기 전에 가정이 사실인지 먼저 잰다. "이 클래스는 제거됐다"를 확인하는 데 명령 한 줄이면 됐는데, 그걸 건너뛰고 세 번을 고쳤다.
에러 메시지는 증상이지 진단이 아니다.
NoClassDefFoundError 는 "없다"고 말하지 않는다. "여기서 안 보인다"고 말한다.