기본 설정으로 앱 최적화를 사용 설정하면 R8은 성능 이점을 극대화하기 위해 광범위한 최적화를 실행합니다. R8은 클래스 필드 및 메서드의 이름 변경, 이동, 삭제를 비롯하여 코드를 대폭 수정합니다. 이로 인해 오류가 발생하면 keep 규칙을 작성하여 코드의 어느 부분을 그대로 두어야 할지 지정해야 합니다.
다음과 같은 경우 R8에서 코드를 잘못 삭제하거나 수정할 수 있습니다.
- 리플렉션: 리플렉션을 사용하여 액세스하는 코드(예:
Class.forName()
또는Method.invoke()
사용) 일반적으로 R8은 이러한 방식으로 액세스할 클래스 또는 메서드를 알 수 없습니다. - 직렬화: 직렬화 및 역직렬화에 필요한 클래스 또는 필드가 R8에서 사용되지 않는 것처럼 보일 수 있습니다 (이는 리플렉션의 또 다른 형태입니다).
- Java 네이티브 인터페이스 (JNI): 네이티브 코드에서 호출되는 Java 메서드입니다. R8은 네이티브 코드를 분석하여 Java에서 다시 호출할 수 있는 항목을 확인하지 않습니다.
이 페이지에서는 R8의 최적화 범위를 제한하는 방법을 설명합니다. 보관할 리소스를 맞춤설정하는 방법은 리소스에 보관 규칙 추가를 참고하세요.
보관 규칙을 추가하는 위치
모듈의 루트 디렉터리에 있는 proguard-rules.pro
파일에 규칙을 추가해야 합니다. 이 파일이 이미 있을 수도 있지만 없는 경우 만들어야 합니다. 파일에 규칙을 적용하려면 다음 코드와 같이 모듈 수준 build.gradle.kts
(또는 build.gradle
) 파일에서 파일을 선언해야 합니다.
Kotlin
android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), // File with your custom rules. "proguard-rules.pro" ) ... } } ... }
Groovy
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile('proguard-android-optimize.txt'), // File with your custom rules. 'proguard-rules.pro' ) } } // ... }
기본적으로 빌드 스크립트에는 proguard-android-optimize.txt
파일도 포함됩니다. 이 파일에는 대부분의 Android 프로젝트에 필요한 규칙이 포함되어 있으므로 빌드 스크립트에 유지해야 합니다.
Keep 규칙 작성 방법
앱 컴파일 중에 R8은 매니페스트 항목 (예: 활동 또는 서비스)에서 시작하여 모든 앱 및 라이브러리 함수 호출을 추적하는 앱의 호출 그래프를 분석하여 앱에 보관해야 하는 코드를 감지합니다. R8은 이러한 방식으로 직접 참조되지 않는 코드를 삭제하므로 실행된 코드가 이 그래프의 일부가 아닌 경우(예: 리플렉션으로 호출된 코드) 문제가 발생할 수 있습니다. 자체 keep 규칙을 작성하여 앱에 유지해야 하는 코드를 R8에 알릴 수 있습니다.
유지 규칙을 추가하려면 proguard-rules.pro
파일에 -keep
줄을 추가합니다.
규칙 문법 유지
Keep 규칙은 일반적으로 다음 형식을 따릅니다.
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
예를 들어 특정 클래스와 모든 멤버를 보존하려면 다음을 사용하세요.
-keep class com.myapp.MyClass { *; }
더 많은 예는 예시 섹션을 참고하세요.
keep 규칙 구성요소의 기능은 다음과 같습니다.
<KeepOption>
를 사용하면 클래스의 어떤 측면을 보존할지 지정할 수 있습니다.유지 옵션 설명 -keep
[{ OptionalMemberSpecification }]
에 나열된 클래스 및 멤버를 보존합니다.-keepclassmembers
클래스의 최적화를 허용합니다. 클래스가 보존되면
[{ OptionalMemberSpecification }]
에 나열된 멤버를 보존합니다.-keepnames
클래스 및 구성원의 삭제를 허용하지만 다른 방식으로 난독화하거나 수정하지 않습니다.
-keepclassmembernames
클래스 및 멤버 삭제를 허용하지만 다른 방법으로 멤버를 난독화하거나 수정하지 않습니다.
-keepclasseswithmembers
구성원이 지정된 패턴과 일치하는 경우 클래스를 삭제하거나 난독화하지 않습니다.
대부분의 경우
-keepclassmembers
를 사용하는 것이 좋습니다.-keepclassmembers
는 가장 많은 최적화를 사용 설정하기 때문입니다. 필요한 경우-keepnames
를 사용합니다.-keep
는 최적화를 허용하지 않으므로 가급적 사용하지 마세요.[OptionalModifier],...]
를 사용하면 클래스의 Java 언어 수정자(예:public
또는final
)를 0개 이상 나열할 수 있습니다.<ClassSpecification>
를 사용하면 keep 규칙을 적용할 클래스 (또는 슈퍼클래스 또는 구현된 인터페이스)를 지정할 수 있습니다. 가장 간단한 경우에는 정규화된 클래스 하나입니다.[{ OptionalMemberSpecification }]
를 사용하면 특정 패턴과 일치하는 클래스와 메서드로만 유지 동작을 필터링할 수 있습니다. 일반적으로 의도한 것보다 더 많이 유지되지 않도록 대부분의 유지 규칙에서 권장됩니다.
Keep 규칙 예시
다음은 잘 설계된 유지 규칙의 예입니다.
서브클래스 생성
이 유지 규칙은 데이터베이스 생성자가 반사에 의해 인스턴스화되도록 androidx.room:room-runtime
내에 패키징됩니다.
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
Android 프레임워크 ObjectAnimator
에서 반사
이 keep 규칙은 ObjectAnimator
가 JNI를 사용하여 네이티브 코드의 getter 또는 setter를 호출할 수 있도록 androidx.vectordrawable:vectordrawable-animated
내에 패키징됩니다. Compose의 최신 애니메이션 시스템에는 이와 같은 keep 규칙이 필요하지 않습니다. 이는 규칙 구조의 예일 뿐입니다.
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
JNI 등록
이 유지 규칙은 androidx.graphics:graphics-path
내에 패키징되어 있으며 네이티브 메서드를 유지하는 데 사용됩니다. 라이브러리가 env->RegisterNatives()
로 네이티브 메서드를 수동으로 등록하는 경우 필요할 수 있습니다.
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}