AX 노트 · 측정

Play Console 'DEX 최적화 39%'의 범인: 쓰지도 않는 Kakao SDK keep 규칙

R8 keep 규칙 하나가 앱과 라이브러리의 public 멤버를 전부 붙잡고 있었고, 그 파일을 지우자 r8.json 기준 39%가 85%로 올랐습니다.

작성 SugarMount Android 개발 읽는 시간 10분 최종 업데이트

Play Console은 2026-09-25에도 한글 띄어쓰기 앱의 최신 번들을 "중급형(최적화 36%, 난독화 39%, 축소 39%)"으로 표시했습니다. 닷새 전에 R8 최적화를 막던 -dontoptimize를 지운 뒤였습니다. 남은 원인은 앱이 쓰지도 않는 Kakao SDK용 proguard 파일이었습니다. 그날 그 파일을 지우자 번들 안 r8.json의 축소 안 된 비율이 61.47%에서 15.18%로 내려갔고(100에서 뺀 환산값 39%→85%), AAB는 18.4MB에서 11.6MB가 됐습니다.

숫자는 SugarMount 앱 저장소(sugarspeller)의 커밋 a597223(2026-09-20)과 e05f8e3(2026-09-25), CHANGELOG 1.6.020·1.6.023 항목, 배포 감시 문서, 그리고 이 글을 쓰며 로컬 릴리스 AAB에서 다시 읽은 r8.json입니다. 기준일은 2026년 10월 20일입니다.

목차 (7)
  1. Play Console의 퍼센트는 r8.json 비율을 뒤집은 값입니다
  2. -dontoptimize를 지우자 최적화 0%가 36%가 됐습니다
  3. 병합된 configuration.txt에 class * 규칙이 있었습니다
  4. 두 번의 수정 전후 r8.json과 크기
  5. AI가 놓친 단서는 오른 난독화 비율이었습니다
  6. 남은 일
  7. 자주 묻는 질문

Play Console의 퍼센트는 r8.json 비율을 뒤집은 값입니다

이 퍼센트는 번들에 든 r8.json의 통계와 숫자가 맞아떨어집니다. Android Gradle Plugin(AGP)은 R8을 돌린 릴리스 AAB 안에 BUNDLE-METADATA/com.android.tools/r8.json을 넣습니다. 그 파일의 stats에는 축소·난독화·최적화를 받지 않은 코드 비율이 들어 있습니다.

unzip -p app-release.aab BUNDLE-METADATA/com.android.tools/r8.json
"stats":{"noObfuscationPercentage":61.48,
         "noOptimizationPercentage":64.27,
         "noShrinkingPercentage":61.47}

100에서 빼면 Play 화면이 나옵니다. 61.47은 축소 39%, 64.27은 최적화 36%였습니다. 이 대응은 저장소의 전후 표에서 맞춰 본 것이고, Google 문서에서 계산식을 확인하지는 않았습니다. 그래도 이 대응으로 Play에 올리기 전에 로컬 빌드만으로 지표를 미리 볼 수 있습니다.

빌드 환경은 AGP 9.4.0, R8 전체 모드(full mode), 리소스 축소 사용, 기본 proguard-android-optimize.txt였습니다. 저장소 기록에는 Play가 이 지표를 2027년 2월까지 해소하라고 요구한다고 적혀 있습니다. Play 화면의 원문은 이 글에서 다시 확인하지 못했습니다.

-dontoptimize를 지우자 최적화 0%가 36%가 됐습니다

2026-09-20 커밋 a597223은 proguard-common.pro에서 -dontoptimize 한 줄을 지웠습니다. 이 줄은 Gson 리플렉션 파싱이 깨질까 봐 일부러 넣어 둔 것이었고, Play Console 최적화 지표를 0%로 묶고 있었습니다. 같은 환경에서 수정 전 HEAD(1.6.019)를 기준선으로 빌드해 비교했습니다.

최적화 안 된 비율은 100%에서 64.25%로 내려갔고, 압축 전 DEX는 16.31MB에서 14.84MB가 됐습니다. 같은 릴리스에서 인사카드 편집기와 이미지 에셋(약 11MB)을 함께 지웠기 때문에 AAB 29.95MB → 18.33MB는 최적화 덕분이 아닙니다. 최적화가 줄인 것은 DEX 1.5MB 안쪽입니다.

난독화 안 된 비율이 54.16%에서 61.46%로 올랐습니다. 그 커밋은 이것을 "앱 코드가 줄어 SDK keep 규칙 쪽 비중이 커진 것"이라고 설명하고 넘어갔습니다. 1.6.020은 2026-09-22에 배포됐습니다. 사흘 뒤 Play Console에 뜬 숫자가 이 글 첫머리의 36/39/39%입니다.

병합된 configuration.txt에 class * 규칙이 있었습니다

R8이 실제로 읽은 규칙은 app/build/outputs/mapping/release/configuration.txt에 한 파일로 모여 있습니다. 기본 규칙, 앱의 .pro 파일 6개, 라이브러리 AAR이 가져온 consumer 규칙까지 전부입니다. 2026-10-09 릴리스 빌드의 병합 결과는 1,369줄로, 처음부터 끝까지 눈으로 읽을 만한 분량입니다. 2026-09-25에 이 파일을 읽다가 아래 블록을 찾았습니다.

# proguard-kakao.pro (2020-12-16 첫 커밋부터 있던 파일, 7줄)
-keep class com.kakao.** { *; }
-keepattributes Signature
-keepclassmembers class * {
  public static <fields>;
  public *;
}
-dontwarn android.support.v4.**,org.slf4j.**,com.google.android.gms.**

셋째 규칙의 class *에는 조건이 없어서, 앱과 모든 라이브러리의 모든 클래스가 걸립니다. 그 클래스들의 public 필드와 메서드는 지워지지도, 이름이 바뀌지도, 인라이닝되지도 않습니다. 그런데 Kakao SDK는 의존성 목록에도 코드에도 없었습니다. 루트 빌드 스크립트의 Kakao 저장소 줄마저 주석 처리돼 있었습니다.

커밋 e05f8e3은 이 파일과 빌드 참조 두 곳(release, debug)을 지웠습니다. 한 번도 빌드에 연결된 적 없는 proguard-retrofit2.pro(29줄)도 같이 지웠습니다.

Android 앱이라면 class *에 거는 무조건 keep 규칙은 넣지 마십시오. 라이브러리에 필요한 규칙은 그 AAR의 consumer 규칙으로 이미 들어옵니다.

두 번의 수정 전후 r8.json과 크기

두 쌍의 측정은 서로 다른 날 다른 커밋을 빌드한 값입니다. 쌍 안에서만 비교하십시오. 09-20의 64.25%와 09-25의 64.27%처럼 같은 설정에서도 소수점 아래가 조금 다릅니다.

항목1.6.019 기준선-dontoptimize 제거 (09-20)kakao 파일 제거 전 (09-25)제거 후 (09-25)
최적화 안 된 비율100%64.25%64.27%15.68%
난독화 안 된 비율54.16%61.46%61.48%15.14%
축소 안 된 비율기록 없음기록 없음61.47%15.18%
Play 방식 환산 (최적화/난독화/축소)최적화 0% (Play 화면)36/39/- (r8.json 환산)36/39/39% (Play 화면)84/85/85 (r8.json 환산, Play 미확인)
DEX16.31MB (압축 전)14.84MB15.6MB (합계)8.2MB
AAB29.95MB18.33MB (에셋 제거분 포함)18.4MB11.6MB
막대그래프: kakao 파일을 지우자 r8.json의 최적화 안 된 비율이 64.27%에서 15.68%로, 난독화 안 된 비율이 61.48%에서 15.14%로, 축소 안 된 비율이 61.47%에서 15.18%로 내려갔습니다.
7줄짜리 Kakao SDK용 파일 하나를 지우자 축소 안 된 비율이 61.47%에서 15.18%로 내려갔습니다.

DEX 감소량으로 보면 규칙 하나를 지운 쪽이 -dontoptimize 제거의 다섯 배였습니다. 09-20에는 DEX가 1.5MB 줄었고, 이번에는 7.4MB(47%)가 줄었습니다. AAB도 6.8MB 작아졌습니다.

막대그래프: -dontoptimize 제거로 DEX가 16.31MB에서 14.84MB로, kakao 파일 제거로 15.6MB에서 8.2MB로 줄었습니다.
DEX 감소량으로 보면 규칙 파일 하나를 지운 쪽이 -dontoptimize 제거의 다섯 배였습니다.

배포 전에는 디버그 키로 서명한 릴리스 APK를 API 34 에뮬레이터에 올렸습니다. 네이버 검사("안갔다→안 갔다, 좋치→좋지", 틀린 수 2가 서버 값과 일치), 검사 뒤 퀴즈 말풍선, 퀴즈 화면, Remote Config 콘텐츠 삽입이 모두 동작했습니다. Gson이 읽는 JSON 키 5종이 릴리스 dex 안에 문자열 그대로 남아 있는 것도 확인했습니다. (헤드리스 에뮬레이터는 screencap이 검게 나와서 uiautomator dump로 화면 글자를 읽었습니다.)

배포 뒤 감시 문서의 판정도 남아 있습니다. 2026-09-22부터 10-03까지 1.6.020, kakao 규칙을 뺀 첫 배포인 1.6.024, 1.6.025 모두 크래시 0건이었고, 판정은 "회귀 없음"이었습니다.

AI가 놓친 단서는 오른 난독화 비율이었습니다

두 커밋 모두 AI 코딩 에이전트(Claude) 세션이 작성했습니다. 09-20 세션은 커밋 메시지에 "원인이 이 한 줄이다"라고 적었습니다. 난독화 안 된 비율이 7%p 넘게 오른 것도 표에 정확히 적었습니다. 다만 그 이유를 "keep 규칙 변화 없음, 비중이 커졌을 뿐"이라는 추정으로 메웠고, 어느 규칙이 코드를 붙잡는지는 열어 보지 않았습니다.

09-25 오후 운영자가 Play Console 화면 캡처를 붙이며, 최적화가 안 된 것처럼 나온다면서 심층 분석을 요청했습니다. 그제야 에이전트가 병합 설정을 열었고, 2020년 첫 커밋부터 있던 7줄짜리 파일이 나왔습니다. 추정 대신 configuration.txt를 먼저 열었다면 닷새 일찍 끝났을 겁니다.

이 일 뒤로 저장소의 에이전트 지침에 두 줄이 생겼습니다. "class *에 거는 keep 규칙은 넣지 않는다"와 "병합 결과는 configuration.txt로 본다"입니다. 릴리스 빌드에서만 나는 R8 문제를 출시 전에 거르는 절차는 AI가 만든 Android 앱, 출시 전에 무엇을 검사하나에 따로 정리했습니다.

남은 일

자주 묻는 질문

Play Console의 DEX 코드 최적화 경고가 있으면 업로드가 막히나요?

2026년 9월 기준으로는 막히지 않았습니다. 최적화 0%와 36%인 번들 모두 정상 배포됐습니다. 저장소 기록에는 Play가 2027년 2월까지 해소를 요구한다고 적혀 있으니 미루지 않는 편이 낫습니다.

Play에 올리기 전에 최적화 비율을 볼 수 있나요?

볼 수 있습니다. 릴리스 AAB에서 BUNDLE-METADATA/com.android.tools/r8.json을 꺼내 stats의 세 값을 100에서 빼면 됩니다. 이 앱에서는 61.47이 Play 화면의 축소 39%와 맞았습니다. 이 대응은 저장소 기록으로 맞춰 본 추정이고, 15.18(85%)이 배포 뒤 Play 화면에 그대로 나왔는지는 아직 기록이 없습니다.

어떤 keep 규칙이 지표를 붙잡는지 어떻게 찾나요?

병합된 configuration.txt에서 class *나 **처럼 범위가 넓은데 조건이 없는 -keep, -keepclassmembers를 찾습니다. 이 앱에서는 쓰지 않는 Kakao SDK용 파일의 -keepclassmembers class * { public *; } 한 블록이었습니다.

이 글은 SugarMount가 직접 측정한 값으로 쓰고, 초안 작성에 AI 코딩 에이전트를 썼습니다.

Android 개발 글 전체 보기 · AX 노트 전체 보기