권장사항 준수

유지 규칙을 사용할 때는 앱의 동작을 유지하면서 이점을 얻을 수 있도록 적절한 수준의 구체성을 확보하는 것이 중요합니다. 유지 규칙에서 피해야 할 사항뿐만 아니라 좋은 패턴에 관해 알아보려면 다음 섹션을 참고하세요.

유지 규칙의 좋은 패턴

잘 정의된 유지 규칙은 최대한 구체적이며 다음 패턴을 준수합니다.

  • 클래스 사양의 경우 다음 예와 같이 가능한 경우 항상 특정 클래스, 기본 클래스 또는 주석이 달린 클래스를 지정합니다.

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • 가능하면 소스 코드에 주석을 사용한 다음 유지 규칙에서 이러한 주석을 직접 타겟팅합니다. 이렇게 하면 코드와 코드를 보존하는 규칙 간에 명확하고 명시적인 링크가 생성되어 구성이 더 강력하고 이해하기 쉬우며 코드 변경 시 손상될 가능성이 줄어듭니다.

    예를 들어 다음 스니펫은 @com.example.DisplayComponent로 주석이 달린 다른 클래스뿐만 아니라 MyClass 클래스를 유지하는 방법을 보여줍니다.

    // In the source code
    @com.example.DisplayComponent
    class MyClass { /* ... */ }
    
    // In the keep rules
    -keep @com.example.DisplayComponent class * {*;}
    

    코드 부분이 보존되는 이유에 관한 의미 있는 컨텍스트를 제공하도록 주석 이름을 지정하는 것이 좋습니다. 예를 들어 디스플레이 구성요소에 일부 부분을 유지해야 하는 앱에는 @DisplayComponent를 사용합니다.

  • 가능하면 멤버 사양을 선언해야 하며 앱이 작동하는 데 유지해야 하는 클래스 부분만 참조해야 합니다. 엄격하게 필요한 경우가 아니라면 선택적 멤버 범위를 { *; }로 정의하여 전체 클래스에 규칙을 적용하지 않는 것이 좋습니다.

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    
  • repackageclasses 전역 옵션을 사용하는 경우 선택적 패키지 이름을 지정하지 마세요. 이렇게 하면 재패키지된 클래스 이름에서 패키지 접두사가 생략되므로 DEX 파일이 더 작아집니다.

  • 리플렉션으로 액세스되는 모든 항목의 유지 규칙을 유지합니다. 명시적 유지 규칙이 없어도 R8에서 이러한 항목을 유지하더라도 향후 코드 변경으로 인해 R8에서 더 이상 이러한 항목을 유지하지 않을 수 있으므로 실제 규칙을 유지하는 것이 중요합니다.

    자체 코드의 리플렉션의 경우 Jetpack Keep을 사용하여 유지보수가 더 쉬운 유지 규칙을 생성할 수 있습니다. 각 주석은 리플렉션을 실행하는 코드에 있으므로 코드를 변경할 때 동일한 위치에서 주석을 업데이트하거나 삭제합니다. 이렇게 하면 규칙이 더 이상 앱에서 반영되지 않는 코드를 보존하지 않습니다. Lint는 주석이 달리지 않은 리플렉션 호출에도 플래그를 지정합니다.

  • 가능하면 -assumenosideeffects 또는 -convertchecknotnull을 사용하여 null 검사를 최적화합니다. 이렇게 하면 앱의 DEX 크기를 크게 줄일 수 있습니다. 자세한 내용은 추가 규칙 유형을 참고하세요.

이러한 가이드라인을 준수할 수 없는 경우 유지해야 하는 코드를 전용 패키지에 일시적으로 격리하고 유지 규칙을 패키지에 적용할 수 있습니다. 하지만 이는 장기적인 해결책이 아닙니다. 자세한 내용은 최적화 점진적 채택을 참고하세요. 패키지에 유지 규칙을 사용하려면 다음 예와 같이 유지 규칙을 정의하세요.

-keepclassmembers class com.example.pkg.** { *; }

피해야 할 사항

유지 규칙 구문에는 여러 옵션이 있지만 측정 가능한 지속 가능한 성능 이점을 얻으려면 다음을 사용하지 않는 것이 좋습니다.

  • -keep class com.example.pkg.** { *; }와 같은 패키지 전체 유지 규칙을 장기적으로 사용하지 마세요. R8을 구성할 때 문제를 해결하기 위해 일시적으로 사용할 수 있습니다. 자세한 내용은 최적화 범위 제한을 참고하세요. 일반적으로 와일드 카드를 사용할 때는 주의하세요. 필요한 코드만 유지해야 합니다.
  • 가능하면 유지 규칙을 복사하여 붙여넣도록 제안하는 라이브러리, 특히 패키지 전체 유지 규칙을 사용하지 마세요. Android에서 잘 작동하도록 설계된 라이브러리는 가능한 경우 리플렉션을 피하고 필요한 경우 소비자 유지 규칙을 삽입해야 합니다.
  • 유지 규칙에서 반전 연산자 !를 사용하지 마세요. 실수로 애플리케이션의 거의 모든 클래스에 규칙을 적용할 수 있습니다.

이러한 규칙을 따를 수 없는 경우 많은 개방형 리플렉션을 사용하고 있을 수 있으므로 리플렉션을 피하거나 리플렉션을 사용하는 라이브러리를 피해야 합니다 (Gson 사례 연구 참고).