라이브러리 현명하게 선택
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
앱 최적화를 사용 설정하려면 Android 최적화와 호환되는 라이브러리를 사용해야 합니다. 라이브러리가 Android 최적화에 맞게 구성되지 않은 경우(예: 관련 keep 규칙을 번들로 묶지 않고 반사를 사용하는 경우) Android 앱에 적합하지 않을 수 있습니다. 이 페이지에서는 일부 라이브러리가 앱 최적화에 더 적합한 이유를 설명하고 선택하는 데 도움이 되는 일반적인 도움말을 제공합니다.
반사보다 codegen을 선호합니다.
일반적으로 리플렉션 대신 코드 생성 (codegen)을 사용하는 라이브러리를 선택해야 합니다. codegen을 사용하면 최적화 도구가 런타임에 실제로 사용되는 코드와 삭제할 수 있는 코드를 더 쉽게 결정할 수 있습니다. 라이브러리가 코드 생성 또는 리플렉션을 사용하는지 파악하기는 쉽지 않지만 몇 가지 신호가 있습니다. 자세한 내용은 도움말을 참고하세요.
코드 생성과 리플렉션에 관한 자세한 내용은 라이브러리 작성자를 위한 최적화를 참고하세요.
라이브러리 선택 시 일반적인 도움말
이 팁을 사용하여 라이브러리가 앱 최적화와 호환되는지 확인하세요.
최적화 문제 확인
새 라이브러리를 고려할 때는 라이브러리의 Issue Tracker와 온라인 토론을 살펴보고 축소 또는 앱 최적화 구성과 관련된 문제가 있는지 확인합니다. 문제가 있는 경우 해당 라이브러리의 대안을 찾아야 합니다. 다음 사항에 유의하세요.
- AndroidX 라이브러리 및 Hilt와 같은 라이브러리는 리플렉션 대신 codegen을 사용하므로 앱 최적화에 적합합니다. 리플렉션을 사용하는 경우 필요한 코드만 유지하도록 최소한의 유지 규칙을 제공합니다.
- 직렬화 라이브러리는 객체를 인스턴스화하거나 직렬화할 때 리플렉션을 사용하여 상용구 코드를 피하는 경우가 많습니다. 리플렉션 기반 접근 방식(예: JSON용 Gson) 대신 codegen을 사용하여 이러한 문제를 방지하는 라이브러리를 찾습니다(예: Kotlin 직렬화 사용).
- 패키지 전체의 유지 규칙을 포함하는 라이브러리는 가급적 피해야 합니다. 패키지 전체의 keep 규칙은 오류를 해결하는 데 도움이 될 수 있지만 광범위한 keep 규칙은 결국 필요한 코드만 유지하도록 미세 조정되어야 합니다. 자세한 내용은 최적화 점진적 도입을 참고하세요.
새 라이브러리를 추가한 후 최적화 사용 설정
새 라이브러리를 추가할 때는 나중에 최적화를 사용 설정하고 오류가 있는지 확인합니다. 오류가 있는 경우 해당 라이브러리의 대안을 찾거나 유지 규칙을 작성합니다. 라이브러리가 최적화와 호환되지 않는 경우 해당 라이브러리에 버그를 신고합니다.
규칙은 중복하여 적용될 수 있습니다.
유지 규칙은 중복하여 적용될 수 있습니다. 즉, 라이브러리 종속 항목에 포함된 특정 규칙은 삭제할 수 없으며 앱의 다른 부분을 컴파일하는 데 영향을 줄 수 있습니다. 예를 들어 라이브러리에 코드 최적화를 사용 중지하는 규칙이 포함된 경우 이 규칙은 전체 프로젝트의 최적화를 사용 중지합니다.
반사 사용 여부 확인 (고급)
라이브러리가 리플렉션을 사용하는지 여부는 코드를 검사하여 알 수 있습니다.
라이브러리가 리플렉션을 사용하는 경우 연결된 keep 규칙을 제공하는지 확인합니다. 다음을 실행하는 라이브러리는 리플렉션을 사용하고 있을 가능성이 높습니다.
잘못된 보관 규칙 필터링 (고급)
실제로 삭제해야 하는 코드를 유지하는 keep 규칙이 있는 라이브러리는 피해야 합니다. 하지만 이를 사용해야 하는 경우 다음 코드와 같이 규칙을 필터링할 수 있습니다.
// 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()
R8이 이 코드를 분석하고 어디서나 인스턴스화된 UserList
또는 User
를 찾지 못하면 필드의 이름을 바꾸거나 사용되지 않는 것처럼 보이는 생성자를 삭제하여 앱이 비정상 종료될 수 있습니다. 유사한 방식으로 다른 라이브러리를 사용하는 경우 앱 최적화를 방해하지 않는지 확인해야 하며, 방해하는 경우 사용하지 않는 것이 좋습니다.
Room과 Hilt는 모두 앱 정의 유형을 생성하지만 리플렉션이 필요하지 않도록 codegen을 사용합니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Choose libraries wisely\n\nTo enable app optimization, you must use libraries that are compatible with\nAndroid optimization. If a library isn't configured for Android optimization---for\nexample, if it uses\n[reflection](https://en.wikipedia.org/wiki/Reflective_programming)\nwithout bundling associated keep rules---it might not be a good fit for an\nAndroid app. This page explains why some libraries are better suited for app\noptimization and provides general tips to help you choose.\n\nPrefer codegen over reflection\n------------------------------\n\nGenerally, you should choose libraries that use\n[code generation (*codegen*)](https://en.wikipedia.org/wiki/Code_generation_(compiler))\ninstead of reflection. With codegen, the optimizer can more easily determine\nwhat code is actually used at runtime and what code can be removed. It can be\ndifficult to tell whether a library uses codegen or reflection, but there are\nsome signs---see the [tips](#tips) for help.\n\nFor more information about codegen versus reflection, see\n[Optimization for library authors](/topic/performance/app-optimization/library-optimization#use-codegen).\n\nGeneral tips when choosing libraries\n------------------------------------\n\nUse these tips to help ensure that your libraries are compatible with app\noptimization.\n\n### Check for optimization issues\n\nWhen considering a new library, look through the library's issue tracker and\nonline discussions to check if there are issues related to minification or\nconfiguring app optimization. If there are, you should try to look for\nalternatives to that library. Keep in mind the following:\n\n- The [AndroidX libraries](/jetpack/androidx) and libraries such as [Hilt](/training/dependency-injection/hilt-android) work well with app optimization because they use codegen instead of reflection. When they do use reflection, they provide minimal keep rules to keep only the code that is needed.\n- Serialization libraries frequently use reflection to avoid boilerplate code when instantiating or serializing objects. Instead of reflection-based approaches (such as Gson for JSON), look for libraries that use codegen to avoid these problems, for example by using [Kotlin Serialization](https://github.com/Kotlin/kotlinx.serialization) instead.\n- Libraries that include package-wide keep rules should be avoided if possible. Package-wide keep rules can help resolve errors, but broad keep rules should eventually be refined to keep only the code that is needed. For more information, see [Adopt optimizations incrementally](/topic/performance/app-optimization/adopt-optimizations-incrementally).\n\n### Enable optimization after adding a new library\n\nWhen you add a new library, enable optimization afterwards and check if there\nare errors. If there are errors, look for alternatives to that library or write\nkeep rules. If a library isn't compatible with optimization, file a bug with\nthat library.\n\n### Rules are additive\n\nBe aware that keep rules are additive. This means that certain rules that a\nlibrary dependency includes cannot be removed and might impact the compilation\nof other parts of your app. For example, if a library includes a rule to disable\ncode optimizations, that rule disables optimizations for your entire project.\n\n### Check for use of reflection (advanced)\n\nYou might be able to tell if a library uses reflection from inspecting its code.\nIf the library uses reflection, check that it provides associated keep rules. A\nlibrary is probably using reflection if it does the following:\n\n- Uses classes or methods from the `kotlin.reflect` or `java.lang.reflect` packages\n- Uses the functions `Class.forName` or `classLoader.getClass`\n- Reads annotations at runtime, for example if it stores an annotation value using `val value = myClass.getAnnotation()` or `val value =\n myMethod.getAnnotation()` and then does something with `value`\n- Calls methods using the method name as a string, for example:\n\n // Calls the private `processData` API with reflection\n myObject.javaClass.getMethod(\"processData\", DataType::class.java)\n ?.invoke(myObject, data)\n\n### Filter out bad keep rules (advanced)\n\nYou should avoid libraries with keep rules that retain code that should really\nbe removed. But if you must use them, you can filter the rules out as shown in\nthe following code: \n\n // If you're using AGP 8.4 and higher\n buildTypes {\n release {\n optimization.keepRules {\n it.ignoreFrom(\"com.somelibrary:somelibrary\")\n }\n }\n }\n\n // If you're using AGP 7.3-8.3\n buildTypes {\n release {\n optimization.keepRules {\n it.ignoreExternalDependencies(\"com.somelibrary:somelibrary\")\n }\n }\n }\n\nCase study: Why Gson breaks with optimizations\n----------------------------------------------\n\nGson is a serialization library that often causes issues with app optimization\nbecause it heavily uses reflection. The following code snippet shows how Gson is\ntypically used, which can easily cause crashes at runtime. Notice that when you\nuse Gson to get a list of User objects, you don't call the constructor or pass a\nfactory to the `fromJson()` function. Constructing or consuming app-defined\nclasses without either of the following is a sign that a library might be using\nopen-ended reflection:\n\n- App class implementing a library, or standard interface or class\n- Code generation plugin like [KSP](https://github.com/google/ksp)\n\n class User(val name: String)\n class UserList(val users: List\u003cUser\u003e)\n\n // This code runs in debug mode, but crashes when optimizations are enabled\n Gson().fromJson(\"\"\"[{\"name\":\"myname\"}]\"\"\", User::class.java).toString()\n\nWhen R8 analyzes this code and doesn't see the `UserList` or `User` instantiated\nanywhere, it can rename fields, or remove constructors which don't seem to be\nused, causing your app to crash. If you are using any other libraries in similar\nways, you should check that they won't interfere with app optimization, and if\nthey do, avoid them.\n\nNote that [Room](/training/data-storage/room) and\n[Hilt](/training/dependency-injection/hilt-android) both construct app defined\ntypes, but use codegen to avoid the need for reflection."]]