$ cd /blog
오류 해결

Flutter 패키지 올렸더니 안드로이드 빌드가 깨졌다 — JVM 타깃 충돌 3연쇄 해결기

홈 화면 위젯 패키지를 최신 버전으로 올린 뒤 'Inconsistent JVM-target compatibility' 오류로 안드로이드 빌드가 멈췄습니다. app 모듈만 고쳐서는 해결되지 않았고, 플러그인 모듈까지 세 단계로 정리해야 했던 과정을 코드와 함께 정리했습니다.


안녕하세요. Jay입니다!

운영 중인 앱에 홈 화면 위젯 기능을 붙이려고 home_widget 패키지를 최신 버전으로 올렸는데요, iOS는 멀쩡히 빌드되는데 안드로이드가 이런 메시지를 뱉으며 멈췄습니다.

Inconsistent JVM-target compatibility detected for tasks
'compileDebugJavaWithJavac' (1.8) and 'compileDebugKotlin' (11).

Flutter로 앱을 만들다 패키지를 올릴 때 꽤 자주 만나는 오류입니다. 검색하면 "app 모듈의 자바 버전을 올려라"는 답이 제일 먼저 나오는데, 저는 그것만으로는 해결되지 않았고 세 단계를 거쳐야 통과했습니다. 같은 곳에서 막히신 분들을 위해 순서대로 정리합니다.

🧩 왜 나는 오류인가

안드로이드 빌드에는 자바 컴파일과 코틀린 컴파일이 함께 돌아가는데, 이 둘이 같은 JVM 바이트코드 버전을 목표로 해야 합니다. 하나는 1.8을 노리고 다른 하나는 11을 노리면 Gradle이 위 오류로 멈춥니다.

최근 패키지들이 JVM 11 이상을 요구하기 시작하면서, 프로젝트는 예전 그대로(1.8)인데 새로 추가한 패키지만 11로 컴파일되는 불일치가 생깁니다. 즉 내가 뭘 잘못한 게 아니라, 올린 패키지가 기준선을 끌어올린 것입니다.

1️⃣ 첫 번째 — app 모듈 타깃 올리기

가장 널리 알려진 조치입니다. android/app/build.gradle에서 자바와 코틀린을 함께 11로 맞춥니다. 둘 중 하나만 올리면 오류가 그대로 납니다.

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }

    kotlinOptions {
        jvmTarget = "11"
    }
}

여기까지 하고 다시 빌드했더니 오류 메시지에 찍히는 모듈 이름만 바뀌어서 또 실패했습니다. 이번엔 제 앱 코드가 아니라 패키지(플러그인) 모듈이 문제였습니다.

2️⃣ 두 번째 — 플러그인 모듈까지 한 번에 통일하기

Flutter 프로젝트에서 각 패키지는 별도의 안드로이드 라이브러리 모듈로 빌드됩니다. 그 모듈들은 각자의 설정을 갖고 있어서, app 모듈만 올려서는 안 맞습니다. 그래서 android/build.gradle(루트)에서 모든 서브 프로젝트의 타깃을 일괄로 맞춰줬습니다.

subprojects {
    plugins.withId("com.android.library") {
        def androidExt = extensions.getByName("android")
        androidExt.compileOptions.sourceCompatibility = JavaVersion.VERSION_11
        androidExt.compileOptions.targetCompatibility = JavaVersion.VERSION_11
    }
    tasks.withType(JavaCompile).configureEach {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
        kotlinOptions.jvmTarget = "11"
    }
}

여기서 중요한 함정이 하나 있습니다. 인터넷 예제 중에는 이 설정을 afterEvaluate { ... } 블록으로 감싸는 코드가 많은데, Flutter 프로젝트 기본 템플릿에 들어 있는 아래 설정과 충돌합니다.

subprojects {
    project.evaluationDependsOn(":app")
}

둘을 같이 쓰면 평가 순서가 꼬이면서 빌드가 실패합니다. 그래서 afterEvaluate 대신 plugins.withIdconfigureEach 같은 지연(lazy) 훅을 써야 합니다. 위 코드가 그 방식입니다. 이걸 모르고 afterEvaluate로 계속 시도하다 시간을 꽤 썼습니다.

3️⃣ 세 번째 — 그래도 남는 모듈은 검증 완화

여기까지 하면 대부분 통과하는데, 저는 마지막에 하나가 더 걸렸습니다. 패키지에 따라 자기만 더 높은 타깃(17)을 요구하는 경우가 있어서 전부 11로 통일하는 게 애초에 불가능했거든요. 이럴 땐 android/gradle.properties에 검증 수준을 낮추는 옵션을 넣습니다.

kotlin.jvm.target.validation.mode=warning

기본값은 error라 불일치가 하나만 있어도 빌드를 멈추는데, warning으로 두면 경고만 남기고 진행합니다. 이건 근본 해결이 아니라 완충 장치라는 점은 분명히 알고 쓰는 게 좋습니다. 서로 다른 타깃이 섞이는 상황 자체를 허용하는 것이니까요. 다만 라이브러리들이 각자 다른 버전을 요구하는 과도기에는 현실적인 선택지이고, 실제로 이 상태로 릴리스 빌드(AAB)까지 정상 생성됐습니다.

✅ 정리 — 순서대로 확인하세요

순서 파일 조치
1 android/app/build.gradle compileOptions + kotlinOptions 함께 11로
2 android/build.gradle subprojects에 lazy 훅으로 일괄 통일 (afterEvaluate 금지)
3 android/gradle.properties 타깃이 섞이면 validation.mode=warning

수정 후에는 flutter clean 한 번 돌리고 다시 빌드하세요. Gradle이 이전 설정을 캐시하고 있어서, 고쳤는데도 같은 오류가 나오는 것처럼 보이는 경우가 있습니다.

💡 Jay의 한 줄 — "패키지 하나 올렸을 뿐인데 왜 이렇게 번지나"

이번 건은 기능 개발이 아니라 버전 승급의 여파로 하루를 썼습니다. 코드는 한 줄도 안 바뀌었는데 빌드 환경 세 곳을 고쳐야 했죠. 이런 종류의 작업은 끝나도 아무 기능이 늘지 않아서 허무한데, 그래도 기록해두면 다음 릴리스에서는 같은 자리에서 안 멈춥니다. 실제로 이 정리 이후 다음 릴리스 빌드는 그대로 통과했습니다.

패키지를 올릴 때는 릴리스 노트에서 최소 요구 JVM/Gradle/AGP 버전이 올라갔는지를 먼저 확인하는 습관을 들이면, 최소한 "왜 갑자기?"라는 당황은 줄일 수 있습니다.

결론

Inconsistent JVM-target compatibility 오류는 app 모듈만 고쳐서는 끝나지 않는 경우가 많습니다. ① app 모듈에서 자바와 코틀린을 같은 버전으로 올리고 ② 루트 Gradle에서 플러그인 모듈까지 lazy 훅으로 통일하고 ③ 그래도 섞이면 검증을 warning으로 완화 — 이 순서로 접근하시면 대부분 해결됩니다. afterEvaluate를 쓰지 않는 것만 꼭 기억하세요.

다음에도 유익한 포스팅으로 찾아오겠습니다. 감사합니다!

📚 참고 / 출처

#Flutter#Android#Gradle#Kotlin#빌드 오류

$ ls related/

더 많은 IT·AI 활용법이 궁금하다면?

매주 새로운 실전 가이드가 업데이트됩니다.

전체 글 보기