Since R8's optimizations update your app's code, it's important to strongly test your app's behaviour to make sure that your app is functioning as expected. In case of unexpected behaviour, use this page as a guide to troubleshoot potential issues after optimization.
While troubleshooting, focus on the following situations:
- Over optimization leading to app crashes: Your app crashes because R8 optimized too much code.
- Unclear or insufficient optimization: R8 did not optimize your app as much as you expected or you need further explanations for the optimizations.
App crashes
If your app crashed after optimizing it with R8, it's typically due to broken reflection. To identify broken reflection, use the following guidelines:
- You observe an exceptions which usually means that the
indicated class, method, or field is being used through reflection.
These exceptions are typically one of:
ClassNotFoundException,NoSuchMethodException,NoSuchFieldException,NoClassDefFoundError,NoSuchMethodError,NoSuchFieldError. - You see code which references reflection with
import kotlin.reflect.*orimport java.lang.reflect.*. - You observe a class constructor being used as follows:
Something::class.constructors. - You see
Class.forName(...).
Solution: Add a keep rule.
Unclear or insufficient optimization
Since rules are applied from your app, as well as included libraries, you might need additional clarity about the rules applied, or need an explanation for why R8 retained certain sections of code that you expected to be optimized.
Ambiguity about the rules applied: Because rules from included libraries also apply to your app, and global options from these libraries also propagate to your app, you might be unsure about which rules are applied.
Solution: Check which rules are applied by viewing the report of all the rules that R8 applies when building your project. You can find this report at
./app/build/outputs/mapping/configuration.txt. This report contains all of the merged rules from every library and module that was used to configure R8, and can be used to identify inefficient rules.Too much code being kept: R8's optimization might retain code that you expected to be removed.
Solution: Use the configuration option
-whyareyoukeepingto help understand why the code was kept. The output contains a path from the kept code to one of your app's entry points. For more information, see-whyareyoukeeping.Difficulty understanding the original stack trace: R8 changes code in various ways, making the stack trace no longer refer to the original code. For example, line numbers and the names of classes and methods can change.
Solution: Starting from With Android Studio Otter 3 Feature Drop and AGP 9.0, Logcat automatically deobfuscates stack traces. However, if you're using an earlier version of Android Studio, you need to manually recover the original stack trace. To recover the original stack trace, use the
retracecommand-line tool, which is bundled with the command-line tools package.To use
retrace, provide the command with the path to a mapping file and a stack trace file. The mapping file, calledmapping.txt, is automatically bundled with your Android App Bundle (AAB). For more details, see the retrace documentation and the Play Console Help Center article about how to deobfuscate crash stack traces. When using Play and Firebase Crashlytics, use themapping.txtfile with the crashes the service collects from app users. The following command shows how you can runretracefrom your project's root:$ANDROID_HOME/cmdline-tools/latest/bin/retrace app/build/outputs/mapping/$releaseVariant/mapping.txt trace.txt
Report bugs
If you're unable to solve an issue with R8, file a bug.