Google released R8 as a replacement for Proguard to help developers shrink their code by generating better output (APK). Compared to Proguard, R8 is considered to be much faster than Proguard.
1. What is R8? - R8 is a tool that converts our java bytecode into optimized dex code.
- It goes through the entire application and then optimizes it like removing unused classes, methods etc.
- It runs at compile time. It helps us reduce the size of our builds and makes our applications more secure.
- R8 uses Proguard rules to modify its default behavior.
(1) Benefits of turning on R8 - Code shrinking (tree shaking): Uses static code analysis to find and remove unreachable code and uninstantiated types, useful for circumventing the 64k reference limit.
- Resource reduction: Remove unused resources, including unused resources in your app's library dependencies.
- Obfuscated code: shorten class and member names to reduce the size of DEX files
- Optimize code: Inspect and rewrite code, selectively inline, remove unused parameters and merge classes to optimize code size.
- Reduce debug information: normalize debug information and compress line number information
- R8 automatically performs the above compile-time tasks, but you can also disable certain tasks or customize R8's behavior through the ProGuard rules file.
- When using a third-party library, you usually only use a small part of it. Without minification, all library code will remain in the application. Verbose code can sometimes improve readability and maintainability.
2. How to use R8 (1) The main functions of the R8 compiler are: - Code shrinking (aka tree shaking) detects and safely removes unused classes, fields, methods, and properties from your app and its library dependencies (making it a very useful tool for getting around the 64k reference limit). For example, if you only use a few APIs from a library dependency, shrinking can identify the library code your app doesn't use and remove only that portion of code from your app.
- Resource shrinking: Remove unused resources from your packaged app, including unused resources from your app's library dependencies. This feature can be used in conjunction with code shrinking so that once you remove unused code, you can also safely remove any resources that are no longer referenced.
- Optimize: Inspect and rewrite code to further reduce the size of your app's DEX file. For example, if R8 detects that the else {} branch of a given if/else statement is never taken, it removes the code for the else {} branch.
- Obfuscation: Rename classes, methods, and fields with meaningless short names to increase the difficulty of reverse engineering, and shorten the names of classes and members to reduce the size of DEX files.
(2) Enabling and disabling R8 To enable minification, obfuscation, and optimization, add the following to your project-level build.gradle file: android { buildTypes { release { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. // Enable R8 code reduction minifyEnabled true // Enables resource shrinking, which is performed by the // Android Gradle plugin. // Enable R8's resource reduction feature shrinkResources true // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. proguardFiles getDefaultProguardFile( 'proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... } Close R8 and add configuration in gradle.properties # Explicitly enable R8 android.enableR8 = true # Disable R8 compiler only for Android Library module android.enableR8.libraries = false # Disable the R8 compiler for all modules android.enableR8 = false R8 normal mode is compatible with Proguard. If Proguard is already used in the original project, you can directly enable R8. At the same time, R8 also has a full mode, but it is not directly compatible with Proguard. You can enable it by setting the following in the gradle.properties file: android.enableR8.fullMode=true The additional optimizations make R8 behave differently from ProGuard, so you may need to add additional ProGuard rules to avoid runtime issues. (3) Customize the code to be retained To force R8 to keep certain code, add the -keep line to the ProGuard rules file, such as -keep public class MyClass Add @Keep annotation to the code you want to keep - Adding @Keep on a class keeps the entire class as is.
- Adding this annotation on a method or field will leave that method/field (and its name) as well as the class name unchanged.
- This annotation is available only if you use the AndroidX annotation library and you include the ProGuard rules file that comes with the Android Gradle plugin.
3. Comparison between R8 and Proguard - For Android apps using the Gradle plugin version 3.4.0 or higher, the project uses R8 by default and no longer uses Proguard for optimization. However, it only uses Proguard rules.
- R8 effectively inlines container classes and removes unused classes, fields, and methods. Proguard reduces the application size by 8.5% and reduces code by 10% compared to R8.
- R8 has more support for Kotlin than Proguard.
- R8 provides better output than Proguard and is faster than Proguard, thus reducing overall build time.
(1) Compare the performance of Proguard and R8 Proguard: When using Proguard, the application code is converted to Java bytecode by the Java compiler. After conversion, Proguard optimizes it using the rules we write. Then dex converts it to optimized Dalvik bytecode. Converting it to Dalvik bytecode takes about 4 steps. R8: - When using R8, the application code is first converted into Java bytecode by the Java compiler, and then R8 is used directly to convert the Java bytecode into Dalvik bytecode.
- By using R8, it directly reduces the steps of converting Java bytecode to Dalvik bytecode from 2 to 1.
- Proguard applies 520 peephole optimizations, which is quite a bit compared to R8. Peephole optimizations are a set of optimizations performed on the code generated by the compiler that improve the performance of the code by making it shorter and faster.
- In Proguard and R8, we have to handle reflection by writing custom configuration.
- R8 is faster than Proguard in executing transformed code.
|