유지 규칙을 사용할 때는 앱의 동작을 유지하면서 이점을 얻을 수 있도록 적절한 수준의 구체성을 확보하는 것이 중요합니다. 보관 규칙에서 좋은 패턴과 피해야 할 사항은 다음 섹션을 참고하세요.
보관 규칙의 좋은 패턴
잘 정의된 보관 규칙은 최대한 구체적입니다.
클래스 사양의 경우 다음 예와 같이 가능하면 항상 특정 클래스, 기본 클래스 또는 주석이 달린 클래스를 지정하세요.
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }
-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }
-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }
가능한 경우 소스 코드에 주석 (예:
@Keep
주석)을 사용한 다음 keep 규칙에서 해당 주석을 직접 타겟팅하세요. 이렇게 하면 코드와 코드를 보존하는 규칙 간에 명확하고 명시적인 링크가 생성되어 구성이 더 강력해지고, 이해하기 쉬워지며, 코드 변경 시 중단될 가능성이 줄어듭니다.예를 들어
androidx.annotation
와 같은 라이브러리는 다음 패턴을 사용합니다.// In your source code @Keep class MyDataClass { /* ... */ } // In your R8 rules -keep @androidx.annotation.DisplayComponent class * {*;}
코드 부분이 보존되는 이유에 관한 의미 있는 컨텍스트를 제공하도록 주석의 이름을 지정하는 것이 좋습니다. 예를 들어 디스플레이 구성요소에서 일부 부분을 유지해야 하는 앱에는
@DisplayComponent
를 사용합니다.가능한 경우 항상 멤버 사양을 선언하고 앱이 작동하는 데 필요한 클래스 부분만 참조해야 합니다. 선택적 멤버 범위를
{ *; }
로 정의하여 전체 클래스에 규칙을 적용하지 않는 것이 좋습니다(엄격하게 필요한 경우 제외).-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }
repackageclasses
전역 옵션을 사용하는 경우 선택적 패키지 이름을 지정하지 마세요. 이렇게 하면 리패키지된 클래스 이름에서 패키지 접두사가 생략되므로 DEX 파일이 작아집니다.
이 가이드라인을 준수할 수 없는 경우 유지해야 하는 코드를 전용 패키지에 일시적으로 격리하고 패키지에 유지 규칙을 적용하면 됩니다. 하지만 장기적인 해결책은 아닙니다. 자세한 내용은 최적화 점진적으로 채택하기를 참고하세요. 패키지에 keep 규칙을 사용하려면 다음 예와 같이 keep 규칙을 정의하세요.
-keepclassmembers class com.example.pkg.** { *; }
피해야 할 사항
보관 규칙 구문에는 다양한 옵션이 있지만 측정 가능한 지속 가능한 성능 이점을 위해 다음은 사용하지 않는 것이 좋습니다.
- 유지 규칙에서 반전 연산자
!
를 사용하지 마세요. 의도치 않게 애플리케이션의 거의 모든 클래스에 규칙이 적용될 수 있습니다. -keep class com.example.pkg.** { *; }
장기 보관과 같은 패키지 전체 보관 규칙을 사용하지 마세요. R8을 구성할 때 문제를 해결하기 위해 일시적으로 사용할 수 있습니다. 자세한 내용은 최적화 범위 제한을 참고하세요. 일반적으로 와일드 카드를 사용할 때는 필요한 코드만 유지해야 합니다.
이 규칙을 따를 수 없다면 개방형 리플렉션을 많이 사용하고 있을 수 있으므로 리플렉션을 피하거나 리플렉션을 사용하는 라이브러리를 피해야 합니다 (Gson 사례 연구 참고).