제품 소식

R8 Keep 규칙 구성 및 문제 해결

7분 길이
2025년 11월 18일
Ajesh Pai의 프로필 보기 벤 와이스의 프로필 보기
Ajesh Pai & Ben Weiss

최신 Android 개발에서 작고 빠르며 안전한 애플리케이션을 제공하는 것은 기본적인 사용자 기대치입니다. 이를 달성하기 위한 Android 빌드 시스템의 기본 도구는 R8  최적화 도구입니다. 이 컴파일러는 축소, 코드 이름 바꾸기 또는 최소화, 앱 최적화를 위해 불필요한 코드 및 리소스 삭제를 처리합니다.

R8을 사용 설정하는 것은 출시를 위해 앱을 준비하는 데 중요한 단계이지만 개발자가 'Keep 규칙' 형식으로 안내를 제공해야 합니다.

이 도움말을 읽은 후 YouTube에서 R8 최적화 도구 사용 설정, 디버깅, 문제 해결에 관한 성능 집중 조명 주간 동영상을 확인하세요.

 

 

Keep 규칙이 필요한 이유

Keep 규칙을 작성해야 하는 이유는 핵심적인 충돌에서 비롯됩니다. R8은 정적 분석 도구이지만 Android 앱은 JNI (Java Native Interface)를 사용하여 리플렉션 또는 네이티브 코드 안팎의 호출과 같은 동적 실행 패턴에 의존하는 경우가 많습니다.

R8은 직접 호출을 분석하여 사용된 코드의 그래프를 빌드합니다. 코드가 동적 방식으로 액세스되면 R8의 정적 분석은 이를 예측할 수 없으며 해당 코드를 사용되지 않은 것으로 식별하고 삭제하여 런타임 비정상 종료가 발생합니다.

Keep 규칙 은 R8 컴파일러에 대한 명시적 안내로, 다음과 같이 명시합니다. '이 특정 클래스, 메서드 또는 필드는 런타임에 동적으로 액세스되는 진입점입니다. 직접 참조를 찾을 수 없더라도 유지해야 합니다.'

Keep 규칙에 관한 자세한 내용은 공식 가이드를 참고하세요.

Keep 규칙을 작성할 위치

애플리케이션의 맞춤 Keep 규칙은 텍스트 파일에 작성됩니다. 관례에 따라 이 파일의 이름은 proguard-rules.pro이며 앱 또는 라이브러리 모듈의 루트에 있습니다. 그런 다음 이 파일은 모듈의 build.gradle.kts 파일의 release 빌드 유형에 지정됩니다.

release {

    isShrinkResources = true

    isMinifyEnabled = true

    proguardFiles(

        getDefaultProguardFile("proguard-android-optimize.txt"),

        "proguard-rules.pro",

    )

}

올바른 기본 파일 사용

getDefaultProguardFile 메서드는 Android SDK에서 제공하는 기본 규칙 집합을 가져옵니다. 잘못된 파일을 사용하면 앱이 최적화되지 않을 수 있습니다. proguard-android-optimize.txt를 사용해야 합니다. 이 파일은 표준 Android 구성요소의 기본 Keep 규칙을 제공하고R8의 코드 최적화를 사용 설정합니다. 오래된 proguard-android.txt는 Keep 규칙만 제공하고 R8의 최적화를 사용 설정하지 않습니다.

progaurd.png

이는 심각한 성능 문제이므로 Android 스튜디오 Narwhal 3 기능 출시부터 개발자에게 잘못된 파일 사용에 관해 경고하기 시작합니다.그리고 Android Gradle 플러그인 버전 9.0부터 오래된 proguard-android.txt 파일을 더 이상 지원하지 않습니다. 따라서 최적화된 버전으로 업그레이드해야 합니다.

Keep 규칙을 작성하는 방법

Keep 규칙은 세 가지 주요 부분으로 구성됩니다.

  1. -keep  또는 -keep-keepclassmembers-keepclassmembers와 같은 옵션
  2. allowshrinking과 같은 선택적 수정자
  3. 일치시킬 코드를 정의하는 클래스 사양

전체 문법 및 예시는 Keep 규칙 추가 가이드를 참고하세요.

Keep 규칙 안티패턴

권장사항뿐만 아니라 안티패턴도 알아야 합니다. 이러한 안티패턴은 오해 또는 문제 해결 바로가기에서 비롯되는 경우가 많으며 프로덕션 빌드의 성능에 치명적일 수 있습니다.

전체 옵션

이러한 플래그는 출시 빌드에서 절대 사용해서는 안 되는 전역 전환입니다. 문제 격리를 위한 임시 디버깅에만 사용됩니다.

-dontotptimize를 사용하면 R8의 성능 최적화가 효과적으로 사용 중지되어 앱이 느려집니다.

-dontobfuscate를 사용하면 모든 이름 바꾸기가 사용 중지되고 -dontshrink를 사용하면 불필요한 코드 삭제가 사용 중지됩니다. 이러한 전역 규칙은 모두 앱 크기를 늘립니다.

더 나은 성능의 앱 사용자 환경을 위해 가능한 한 프로덕션 환경에서 이러한 전역 플래그를 사용하지 마세요.

과도하게 광범위한 Keep 규칙

R8의 이점을 무효화하는 가장 쉬운 방법은 과도하게 광범위한 Keep 규칙을 작성 하는 것입니다. 아래와 같은 Keep 규칙은 R8 최적화 도구에 이 패키지 또는 하위 패키지모든 클래스를 축소, 난독화, 최적화하지 않도록 지시합니다. 이렇게 하면 전체 패키지에 대한 R8의 이점이 완전히 삭제됩니다. 대신 좁고 구체적인 Keep 규칙을 작성해 보세요.

-keep class com.example.package.** { *;} // WIDE KEEP RULES CAUSE PROBLEMS

반전 연산자 (!)

반전 연산자 (!)는 규칙에서 패키지를 제외하는 강력한 방법인 것 같습니다. 하지만 그렇게 간단하지 않습니다. 예를 들어보겠습니다.

-keep class !com.example.my_package.** { *; } // USE WITH CAUTION

이 규칙은 " 클래스를 유지하지 않음com.example.package." 을 의미한다고 생각할 수 있습니다. 하지만 실제로 "전체 애플리케이션에서 com.example.package에 없는 모든 클래스, 메서드, 속성을 유지 ." 를 의미합니다. 이 내용이 놀라웠다면 R8 구성에서 부정문을 확인하는 것이 좋습니다.

Android 구성요소의 중복 규칙

또 다른 일반적인 실수는 앱의 Activities, Services 또는 BroadcastReceivers에 Keep 규칙을 수동으로 추가하는 것입니다. 이는 불필요 합니다. 기본 proguard-android-optimize.txt 파일에는 이러한 표준 Android 구성요소가 기본적으로 작동하도록 하는 관련 규칙이 이미 포함되어 있습니다.

또한 많은 라이브러리가 자체 Keep 규칙을 가져옵니다. 따라서 이러한 규칙을 직접 작성할 필요가 없습니다. 사용 중인 라이브러리의 Keep 규칙에 문제가 있는 경우 라이브러리 작성자에게 문의하여 문제를 확인하는 것이 가장 좋습니다.

Keep 규칙 권장사항

이제 하지 말아야 할 사항을 알았으니 권장사항에 관해 이야기해 보겠습니다.

좁은 Keep 규칙 작성

좋은 Keep 규칙은 가능한 한 좁고 구체적 이어야 합니다. 필요한 항목만 보존하여 R8이 다른 모든 항목을 최적화할 수 있도록 해야 합니다.

규칙품질

 

-keep class com.example.** { ; }

 

낮음: 전체 패키지 및 하위 패키지를 유지합니다.

 

-keep class com.example.MyClass { ; }

 

낮음: 전체 클래스를 유지합니다. 여전히 너무 넓을 수 있습니다.
-keepclassmembers class com.example.MyClass {

    private java.lang.String secretMessage;

    public void onNativeEvent(java.lang.String);

}
높음: 특정 클래스의 관련 메서드와 속성만 유지됩니다.

공통 상위 요소 사용

여러 데이터 모델에 대해 별도의 Keep 규칙을 작성하는 대신 공통 기본 클래스 또는 인터페이스를 타겟팅하는 규칙을 하나 작성합니다. 아래 규칙은 이 인터페이스를 구현하는 클래스의 모든 멤버를 유지하도록 R8에 지시하며 확장성이 뛰어납니다.

# Keep all fields of any class that implements SerializableModel

-keepclassmembers class * implements com.example.models.SerializableModel {

    <fields>;

}

주석을 사용하여 여러 클래스 타겟팅

맞춤 주석 (예: @Serialize)을 만들고 이를 사용하여 필드를 보존해야 하는 클래스에 '태그'를 지정합니다. 이는 또 다른 깔끔하고 선언적이며 확장성이 뛰어난 패턴입니다. 사용 중인 프레임워크의 기존 주석에 대한 Keep 규칙을 만들 수도 있습니다.

# Keep all fields of any class annotated with @Serialize

-keepclassmembers class * {

    @com.example.annotations.Serialize <fields>;

}

올바른 Keep 옵션 선택

Keep 옵션은 규칙의 가장 중요한 부분입니다. 잘못된 옵션을 선택하면 불필요하게 최적화가 사용 중지될 수 있습니다.

Keep 옵션기능
-keep클래스 및 선언에 언급된 멤버 가 삭제되거나 이름이 바뀌지 않도록 합니다.
-keepclassmembers지정된 멤버가 삭제되거나 이름이 바뀌지 않도록 하지만 클래스 자체는 삭제할 수 있습니다. 단, 삭제되지 않는 클래스에만 해당됩니다.
-keepclasseswithmembers조합: 지정된 모든 멤버가 있는 경우에만 클래스 멤버를 유지합니다.

Keep 옵션에 관한 자세한 내용은 Keep 옵션 문서를 참고하세요.

수정자를 사용하여 최적화 허용

allowshrinkingallowobfuscation과 같은 수정자는 광범위한 -keep 규칙을 완화하여 R8에 최적화 기능을 다시 제공합니다. 예를 들어 기존 라이브러리에서 전체 클래스에 -keep을 사용하도록 강제하는 경우 축소 및 난독화를 허용하여 일부 최적화를 복구할 수 있습니다.

# Keep this class, but allow R8 to remove it if it's unused and allow R8 to rename it.

-keep,allowshrinking,allowobfuscation class com.example.LegacyClass

추가 최적화를 위한 전역 옵션 추가

Keep 규칙 외에도 R8 구성 파일에 전역 플래그를 추가하여 최적화를 더욱 장려할 수 있습니다.

-repackageclasses는 R8에 난독화된 모든 클래스를 단일 패키지로 이동하도록 지시하는 강력한 옵션입니다. 이렇게 하면 중복된 패키지 이름 문자열이 삭제되어 DEX 파일에서 상당한 공간이 절약됩니다.

-allowaccessmodification을 사용하면 R8이 액세스 권한을 확대 (예: private에서 public)하여 더 적극적인 인라인을 사용 설정할 수 있습니다. 이제 proguard-android-optimize.txt을 사용할 때 기본적으로 사용 설정됩니다.

경고: 라이브러리 작성자는 이러한 전역 최적화 플래그를 소비자 규칙에 추가해서는 안 됩니다. 이러한 플래그는 전체 앱에 강제로 적용되기 때문입니다.

그리고 더 명확하게 하기 위해 Android Gradle 플러그인 버전 9.0에서는 라이브러리의 전역 최적화 플래그를 완전히 무시하기 시작합니다. 

라이브러리 권장사항

모든 Android 앱은 어떤 식으로든 라이브러리에 의존합니다. 따라서 라이브러리 권장사항에 관해 이야기해 보겠습니다.

라이브러리 개발자

라이브러리가 리플렉션 또는 JNI를 사용하는 경우 소비자에게 필요한 Keep 규칙을 제공해야 합니다. 이러한 규칙은 consumer-rules.pro 파일에 배치되며, 이 파일은 라이브러리의 AAR 파일 내에 자동으로 번들로 제공됩니다.

android {

    defaultConfig {

        consumerProguardFiles("consumer-rules.pro")

    }

    ...

}

라이브러리 소비자

문제가 있는 Keep 규칙 필터링

문제가 있는 Keep 규칙이 포함된 라이브러리를 사용해야 하는 경우 AGP 9.0부터 build.gradle.kts 파일에서 필터링할 수 있습니다. 이렇게 하면 R8이 특정 종속 항목에서 가져온 규칙을 무시하도록 지시합니다.

release {

    optimization.keepRules {

        // Ignore all consumer rules from this specific library

        it.ignoreFrom("com.somelibrary:somelibrary")

    }

}

가장 좋은 Keep 규칙은 Keep 규칙이 없는 것입니다.

궁극적인 R8 구성 전략은 Keep 규칙을 작성할 필요성을 완전히 없애는 것 입니다. 많은 앱에서 리플렉션보다 코드 생성 을 선호하는 최신 라이브러리를 선택하여 이를 달성할 수 있습니다. 코드 생성을 사용하면 최적화 도구가 런타임에 실제로 사용되는 코드와 삭제할 수 있는 코드를 더 쉽게 확인할 수 있습니다. 또한 동적 리플렉션을 사용하지 않으면 '숨겨진' 진입점이 없으므로 Keep 규칙이 필요하지 않습니다. 새 라이브러리를 선택할 때는 항상 리플렉션보다 코드 생성을 사용하는 솔루션을 선호하세요.

라이브러리를 선택하는 방법에 관한 자세한 내용은 라이브러리 현명하게 선택을 참고하세요.

R8 구성 디버깅 및 문제 해결

R8이 유지해야 하는 코드를 삭제하거나 APK가 예상보다 큰 경우 이러한 도구를 사용하여 문제를 진단하세요.

중복 및 전역 Keep 규칙 찾기

R8은 수십 개의 소스에서 규칙을 병합하므로 '최종' 규칙 집합이 무엇인지 알기 어려울 수 있습니다. proguard-rules.pro 파일에 이 플래그를 추가하면 전체 보고서가 생성됩니다.

# Outputs the final, merged set of rules to the specified file

-printconfiguration build/outputs/logs/configuration.txt

이 파일을 검색하여 중복 규칙을 찾거나 문제가 있는 규칙 (예: -dontoptimize)을 포함한 특정 라이브러리로 다시 추적할 수 있습니다.

R8에 문의: 이 항목을 유지하는 이유는 무엇인가요?

삭제될 것으로 예상되는 클래스가 앱에 여전히 있는 경우 R8에서 그 이유를 알려줄 수 있습니다. 이 규칙을 추가하기만 하면 됩니다.

# Asks R8 to explain why it's keeping a specific class

class com.example.MyUnusedClass

-whyareyoukeeping 

빌드 중에 R8은 해당 클래스를 유지하게 만든 참조의 정확한 체인을 출력하므로 참조를 추적하고 규칙을 조정할 수 있습니다.

전체 가이드는 R8 문제 해결 섹션을 참고하세요.

다음 단계

R8은 Android 앱 성능을 개선하는 강력한 도구입니다. 그 효과는 정적 분석 엔진으로서의 작동 방식을 올바르게 이해하는 데 달려 있습니다.

구체적인 멤버 수준 규칙을 작성하고, 상위 요소와 주석을 활용하고, 올바른 Keep 옵션을 신중하게 선택하면 필요한 항목만 정확하게 보존할 수 있습니다. 가장 고급 관행은 리플렉션 기반 이전 버전보다 최신 코드 생성 기반 라이브러리를 선택하여 규칙의 필요성을 완전히 없애는 것입니다.

성능 집중 조명 주간을 따라가면서 YouTube에서 오늘의 집중 조명 주간 동영상을 확인하고 R8 챌린지를 계속 진행하세요. R8 사용 설정 또는 문제 해결에 관한 질문은 #optimizationEnabled를 사용하세요. 최선을 다해 도와드리겠습니다.

이제 직접 혜택을 확인해 보세요.

앱에 R8 전체 모드를 오늘 사용 설정해 보세요.

  1. 개발자 가이드에 따라 시작하세요. 앱 최적화 사용 설정.
  2. 여전히 proguard-android.txt를 사용하는지 확인하고 proguard-android-optimize.txt로 바꿉니다.
  3. 그런 다음 영향을 측정 합니다. 차이를 느끼는 것뿐만 아니라 확인 하세요.  GitHub의 Macrobenchmark 샘플 앱에서 코드를 조정하여 시작 전후의 시작 시간을 측정하여 성능 향상을 측정합니다.

앱의 성능이 크게 개선될 것이라고 확신합니다.

이때 소셜 태그 #AskAndroid를 사용하여 질문을 보내주세요. 한 주 내내 Google 전문가가 질문을 모니터링하고 답변해 드립니다.

내일은 기준 프로필 및 시작 프로필을 사용한 프로필 기반 최적화에 관해 이야기하고, 지난 출시에서 Compose 렌더링 성능이 개선된 방법을 공유하고, 백그라운드 작업의 성능 고려사항을 공유할 예정이니 계속 지켜봐 주세요.

작성자:
계속 읽기