이 글에서 다루는 내용

이 글에서는 Flutter Android 앱을 release 모드로 빌드할 때 마주친 세 가지 문제, 즉 keystore.properties 변수 참조 오류, R8 코드 축소 단계에서의 ML Kit 누락 클래스 에러, 그리고 release signingConfig 전환을 해결한 과정을 다룹니다.

문제 1 — keystoreProperties 참조 오류

android/app/build.gradle.kts에 아래 코드만 있고 keystoreProperties 변수 선언이 빠져 있어 컴파일이 실패했습니다.

signingConfigs {
    create("release") {
        keyAlias = keystoreProperties["keyAlias"] as String?
        keyPassword = keystoreProperties["keyPassword"] as String?
        storeFile = keystoreProperties["storeFile"]?.let { file(it as String) }
        storePassword = keystoreProperties["storePassword"] as String?
    }
}

에러 메시지는 Unresolved reference: keystoreProperties였습니다. 변수 선언과 Properties 파일 로드 코드를 파일 상단에 추가해서 해결했습니다.

import java.util.Properties
import java.io.FileInputStream

val keystoreProperties = Properties().apply {
    val keystorePropertiesFile = rootProject.file("keystore.properties")
    if (keystorePropertiesFile.exists()) {
        load(FileInputStream(keystorePropertiesFile))
    }
}

문제 2 — R8 Missing Classes 에러

bundleRelease 태스크 중 R8이 google_mlkit_text_recognition 플러그인의 중국어·일본어·한국어·데바나가리 언어 모듈 클래스를 찾지 못해 빌드가 실패했습니다.

ERROR: R8: Missing class com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions
...
Execution failed for task ':app:minifyReleaseWithR8'.

ML Kit의 언어별 인식 모듈은 선택적 의존성이라 플러그인 코드에서 참조만 존재하고 실제 클래스는 별도로 추가해야 들어옵니다. 해결책은 두 단계입니다.

2-1. 사용하지 않는 언어는 ProGuard keep 규칙으로 경고 억제

android/app/proguard-rules.pro를 생성합니다.

-dontwarn com.google.mlkit.vision.text.chinese.**
-dontwarn com.google.mlkit.vision.text.devanagari.**
-dontwarn com.google.mlkit.vision.text.japanese.**

2-2. 실제 사용하는 한국어 모듈은 의존성으로 추가

android/app/build.gradle.kts에 다음을 추가합니다.

dependencies {
    implementation("com.google.mlkit:text-recognition-korean:16.0.1")
}

release 빌드가 ProGuard 규칙 파일을 참조하도록 buildTypes.release도 수정했습니다.

buildTypes {
    release {
        signingConfig = signingConfigs.getByName("release")
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
    }
}

문제 3 — debug 서명으로 release 빌드됨

Flutter가 기본 생성하는 build.gradle.kts는 release에 signingConfigs.getByName("debug")를 사용하도록 주석과 함께 설정돼 있습니다. Play Console에 업로드하면 "디버그 모드로 서명한 APK 또는 App Bundle을 업로드했습니다" 오류가 납니다. 위 buildTypes.release 수정에서 getByName("release")로 변경해 실제 release keystore가 사용되도록 했습니다.

최종 build.gradle.kts 구조

import java.util.Properties
import java.io.FileInputStream

plugins { /* ... */ }

val keystoreProperties = Properties().apply {
    val keystorePropertiesFile = rootProject.file("keystore.properties")
    if (keystorePropertiesFile.exists()) {
        load(FileInputStream(keystorePropertiesFile))
    }
}

android {
    signingConfigs {
        create("release") {
            keyAlias = keystoreProperties["keyAlias"] as String?
            keyPassword = keystoreProperties["keyPassword"] as String?
            storeFile = keystoreProperties["storeFile"]?.let { file(it as String) }
            storePassword = keystoreProperties["storePassword"] as String?
        }
    }

    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

dependencies {
    implementation("com.google.mlkit:text-recognition-korean:16.0.1")
}