앱 최적화를 사용 설정하려면 Android 최적화와 호환되는 라이브러리를 사용해야 합니다. 라이브러리가 Android 최적화를 위해 구성되지 않은 경우(예: 연결된 유지 규칙을 번들링하지 않고 리플렉션을 사용하는 경우) Android 앱에 적합하지 않을 수 있습니다. 이 페이지에서는 일부 라이브러리가 앱 최적화에 더 적합한 이유를 설명하고 선택에 도움이 되는 일반적인 팁을 제공합니다.
라이브러리 선택 시 일반적인 팁
이러한 팁을 사용하여 라이브러리가 앱 최적화와 호환되는지 확인하세요.
리플렉션보다 코드 생성 선호
리플렉션 대신 코드 생성 (codegen) 을 사용하는 라이브러리를 선택합니다. codegen을 사용하면 최적화 도구가 런타임에 실제로 사용되는 코드와 삭제할 수 있는 코드를 확인할 수 있습니다. 라이브러리가 codegen을 사용하는지 리플렉션을 사용하는지 확인하기 어려울 수 있지만 몇 가지 징후가 있습니다. 도움이 되는 팁을 참고하세요.
codegen과 리플렉션에 관한 자세한 내용은 Optimization for library authors를 참고하세요.
리플렉션 사용 확인 (고급)
라이브러리의 코드를 검사하여 리플렉션을 사용하는지 확인할 수 있습니다. 라이브러리가 리플렉션을 사용하는 경우 연결된 유지 규칙을 제공하는지 확인합니다. 라이브러리는 다음을 실행하는 경우 리플렉션을 사용할 가능성이 높습니다.
kotlin.reflect또는java.lang.reflect패키지의 클래스 또는 메서드를 사용합니다.Class.forName또는classLoader.getClass함수를 사용합니다.- 런타임에 주석을 읽습니다. 예를 들어 주석 값
을
val value = myClass.getAnnotation()또는val value = myMethod.getAnnotation()을 사용하여 저장한 다음value로 작업을 실행합니다. 다음 예와 같이 메서드 이름을 문자열로 사용하여 메서드를 호출합니다.
// Calls the private `processData` API with reflection myObject.javaClass.getMethod("processData", DataType::class.java) ?.invoke(myObject, data)
최적화 문제 확인
새 라이브러리를 고려할 때는 라이브러리의 문제 추적기 및 온라인 토론을 살펴보고 축소 또는 앱 최적화 구성과 관련된 문제가 있는지 확인합니다. 문제가 있는 경우 해당 라이브러리의 대안을 찾아야 합니다. 다음 사항에 유의하세요.
- AndroidX 라이브러리 및 Hilt와 같은 라이브러리는 리플렉션 대신 codegen을 주로 사용하므로 앱 최적화와 잘 작동합니다. 리플렉션을 사용하는 경우 필요한 코드만 유지하기 위해 최소한의 유지 규칙을 제공합니다.
- 직렬화 라이브러리는 객체를 인스턴스화하거나 직렬화할 때 상용구 코드를 방지하기 위해 리플렉션을 자주 사용합니다. 리플렉션 기반 접근 방식(예: JSON용 Gson) 대신 codegen을 사용하여 이러한 문제를 방지하는 라이브러리(예: Kotlin 직렬화 또는 codegen이 포함된 Moshi 사용)를 찾습니다.
- 가능하면 패키지 전체 유지 규칙이 포함된 라이브러리를 사용하지 마세요. 패키지 전체 유지 규칙은 오류를 해결하는 데 도움이 될 수 있지만 광범위한 유지 규칙은 결국 필요한 코드만 유지하도록 세분화해야 합니다. 자세한 내용은 최적화 점진적 채택을 참고하세요.
- 서드 파티 라이브러리를 사용하는 앱을 게시하기 전에 R8 구성 분석기를 사용하여 제공된 유지 규칙을 감사합니다. 보고서를 검토하여 라이브러리의 유지 규칙이 너무 광범위하여 R8이 코드베이스에서 중요한 최적화를 실행하지 못하도록 하는지 확인할 수 있습니다. 이 검사를 통해 선택한 라이브러리가 앱의 성능 목표와 일치하고 불필요한 구성 블로트를 도입하지 않는지 확인할 수 있습니다.
- 라이브러리에서는 특히 패키지 전체 유지 규칙의 경우 문서에서 유지 규칙을 복사하여 프로젝트의 파일에 붙여넣을 필요가 없어야 합니다. 이러한 규칙은 장기적으로 앱 개발자에게 유지보수 부담이 되며 시간이 지남에 따라 최적화하고 변경하기 어렵습니다.
새 라이브러리를 추가한 후 최적화 사용 설정
새 라이브러리를 추가할 때는 나중에 최적화를 사용 설정하고 오류가 있는지 확인합니다. 오류가 있는 경우 해당 라이브러리의 대안을 찾거나 유지 규칙을 작성합니다. 라이브러리가 최적화와 호환되지 않는 경우 해당 라이브러리에 버그를 신고합니다.
잘못된 유지 규칙 필터링 (고급)
유지 규칙은 중복하여 적용될 수 있습니다. 즉, 라이브러리 종속 항목이 포함하는 특정 규칙은 삭제할 수 없고 앱의 다른 부분을 컴파일하는 데 영향을 줄 수 있습니다. 예를 들어 라이브러리가 코드 최적화를 사용 중지하는 규칙을 포함하는 경우 이 규칙은 전체 프로젝트의 최적화를 사용 중지합니다.
실제로 삭제해야 하는 코드를 유지하는 유지 규칙이 있는 라이브러리는 사용하지 않는 것이 좋습니다. 하지만 사용해야 하는 경우 다음 코드와 같이 규칙을 필터링할 수 있습니다.
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
우수사례: Gson이 최적화와 호환되지 않는 이유
Gson은 리플렉션을 많이 사용하므로 앱 최적화에 문제를 일으키는 직렬화 라이브러리입니다. 다음 코드 스니펫은 일반적으로 Gson이 사용되는 방법을 보여주며, 이로 인해 런타임에 비정상 종료가 발생할 수 있습니다. Gson을 사용하여 User 객체 목록을 가져올 때는 생성자를 호출하거나 팩터리를 fromJson() 함수에 전달하지 않습니다. 다음 중 하나 없이 앱 정의 클래스를 구성하거나 사용하는 것은 라이브러리가 개방형 리플렉션을 사용할 수 있다는 신호입니다.
- 라이브러리 또는 표준 인터페이스 또는 클래스를 구현하는 앱 클래스
- KSP와 같은 코드 생성 플러그인
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
Gson에서 R8이 작동하는 방식을 이해하려면 Gson 소비자 규칙을 참고하세요. R8
이 이 코드를 분석하고 UserList 또는 User가 인스턴스화된
위치를 찾지 못하면 필드 이름을 바꾸거나 사용되지 않는 생성자를 삭제하여 앱이 비정상 종료될 수 있습니다. 다른 라이브러리를 비슷한 방식으로 사용하는 경우 앱 최적화를 방해하지 않는지 확인하고 방해하는 경우 사용하지 않아야 합니다.
최신 Gson 버전에서 @SerializedName 사용
Gson의 소비자 규칙과 호환되는 방식으로 데이터 모델을 정의하려면 다음 스니펫과 같이 필드에 @SerializedName을 주석 처리합니다.
import com.google.gson.annotations.SerializedName
class User(@SerializedName("name") val name: String)
class UserList(@SerializedName("users") val users: List<User>)
@SerializedName 주석을 사용하면 R8이 모델
클래스를 Gson 버전 2.11.0 이상에 번들링된 유지 규칙과 일치시킬 수 있습니다.
R8은 주석 처리된 필드와 필요한 생성자를 자동으로 보존하므로 프로젝트에서 수동 ProGuard 구성을 유지할 필요 없이 라이브러리의 번들링된 규칙을 사용할 수 있습니다.
Room, Hilt, codegen이 포함된 Moshi는 앱 정의 유형을 구성하지만 리플렉션의 필요성을 방지하기 위해 codegen을 사용합니다.