• In the previous article Android Master notes – package volume optimization mentioned by compilation optimization package volume, involving ProGuard, D8, R8, ProGuard and package volume optimization scheme has been introduced in detail, so today we will talk about D8 and R8;

D8

  • D8 is a faster Dex compiler designed to replace DX and generate smaller APK;
Benefits of unlocking D8
  1. Compile faster and take less time
  2. Smaller memory footprint at compile time
  3. Dex files are smaller
  4. Dex files have better runtime performance
  5. Support for using the Java 8 language in code
On and off
  • Android Studio 3.0 requires you to actively add android.enableD8=true to the gradle.properties file
  • D8 as an alternative to DX,Android Studio 3.1 starts with D8 as the default Dex compiler.
  • To disable D8, add the following configuration to gradle.properties:
Android. EnableD8 = false / / close the D8 to DX - android. EnableD8. Desugaring = false / / back to the previous behavior, let off sugar occurs after the Java compiler, the class bytecode still follow the Java 7 formatCopy the code
Performing incremental builds
  • To speed up builds during development (for example, to speed up continuous integration builds), you can instruct D8 to compile only a portion of your project’s Java bytecode;
  • For example, if class-by-class dexing is enabled, you only need to recompile classes that have changed since the last build (D8 cannot automatically detect which bytecode files have been modified, so you need to specify the class list manually) :
// Perform incremental builds of several classes, Class r.class --intermediate --file-per-class --output d8 mainActivity. class r.class --intermediate --file-per-class --output for incremental builds ~/build/intermediate/dexCopy the code
  • You can use –main-dex-list to specify the classes you want d8 to compile into the main dex file
d8 ~/build/intermediate/dex --release --main-dex-list ~/build/classes.txt --output ~/build/release/dex
Copy the code
Support Java8
  • Transforms these functional language features into bytecode that runs on the Android platform through a compilation process called “deicing”, and D8 deicing does not generate desugar directories under the Transforms directory.
  • The Android Studio and Android Gradle plug-ins contain the classpath resources required for d8 to enable desugaring.
  • When using D8 from the command line, you need to manually add some resources:
  1. –lib: mark the android.jar path in the target Android SDK
  2. — CLASspath: The compiled Java bytecode that marks the part of the project that is not currently intended to be compiled into DEX bytecode, but is needed when other classes are compiled into DEX bytecode. For example, if your code uses default and static interface methods (a Java 8 language feature), you need to use this tag to specify the path to all of your Java bytecodes for your project, even if you don’t plan to compile all of your Java bytecodes into DEX bytecodes. This is because D8 needs this information to understand your project’s code and parse calls to interface methods
  • The example performs an incremental build on a class that accesses a default interface method:
d8 MainActivity.class --intermediate --file-per-class --output ~/build/intermediate/dex
--lib android_sdk/platforms/api-level/android.jar
--classpath ~/build/javac/debug
Copy the code
New in Java8: interface default methods and static methods
  • Before JDK1.8, interfaces did not provide any concrete implementation;
  • Starting with JDK1.8, the interface allows you to define default and static methods

R8

  • The R8 was previously built as a D8+ProGuard. The R8 integrates ProGuard and D8 tools to accelerate build time and reduce output APK size.
Benefits of turning on R8
  1. Code reduction (tree shaking) : Using static code analysis to find and remove unreachable code and uninstantiated types is useful for circumventing the 64K reference limit;
  2. Resource reduction: Removes unused resources, including those from application library dependencies.
  3. Obfuscation code: Shorten the names of classes and members to reduce the size of DEX files
  4. Optimize code: Review and rewrite code, selectively inline, remove unused parameters and merge classes to optimize code size
  5. Reduce debugging information: Normalize debugging information and compress line number information.
  • R8 automatically performs the above compile-time tasks, but you can also disable some tasks or customize the behavior of R8 through the ProGuard rule file.
  • When you use a third-party library, you usually only use a small portion of it. Without compression, all library code remains in the application. Verbose code can sometimes improve readability and maintainability: for example, using meaningful variable names and builder patterns to help others examine and understand the code more easily; But these patterns increase the amount of code, and there is usually a lot of room for compression in the code we write ourselves.
On and off
  • For Android Studio 3.3, add android.enableR8=true to your gradle.properties project
  • R8 is the default compiler for Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher (no longer using ProGuard to perform compile-time code optimizations), Used to convert the project’s Java bytecode to the DEX format to run on the Android platform.
  • However, reduction, obfuscation, and code optimization are disabled by default when you create a new project. These compile-time optimizations can increase the build time of a project and can introduce errors if the code to be retained is not adequately customized.
  1. To enable code reduction, set the minifyEnable property to True in the main build.gradle file of your application
  2. Enable resource reduction: Set shrinkResources to true in your application’s main build.gradle file
  • Resource reduction only works when used in conjunction with code reduction. After the code reductor removes all unused code, the resource reductor can determine the resources that the application still needs to use, especially when adding a code base that contains the resources. Unused library code must be removed to make the library resource unreferenced and thus removable by the resource reductor.
  1. When you create a new project or module, the IDE creates a/ProGuard-rules.pro file so that you can add your own rules.
android { ... BuildTypes {release {shrinkResources true // Enable R8 minifyEnabled true // Enable R8 code reduction proguardFiles //1. The Android Gradle plugin generates proguard-Android-optimise.txt, which contains rules useful for most Android projects, and enables the @keep * annotation. getDefaultProguardFile('proguard-android-optimize.txt'), //2. Pro file 'ProGuard-rules.pro' //3. AAR library is created in the root directory of the module: The < library - dir > / proguard. TXT, JAR libraries: <library-dir>/ meta-INF /proguard/ / Because proGuard rules are cumulative, AAR library dependencies contain certain rules that cannot be removed and may affect compilation of other parts of the application. For example, if a library contains a rule to disable code tuning, that rule deactivates tuning for the entire project. //4. Android Resource Packaging Tool 2 (AAPT2): // After building a project with minifyEnabled True,AAPT2 generate retention rules based on references to classes, layouts, and other application resources in the application list. / / file path for: < module - dir > / build/intermediates/proguard - rules/debug/aapt_rules. TXT / / 5. Custom configuration files: See adding Additional configurations below}}}Copy the code
Adding Additional Configurations
  • You can add rules specific to each build variant by adding an additional proguardFiles property to the corresponding productFlavor code block
android {
    ...
    buildTypes {
        release {
            ...
        }
    }
    flavorDimensions "version"
    productFlavors {
        flavor1 {
            ...
        }
        flavor2 {
            proguardFile 'flavor2-rules.pro'
        }
    }
}
Copy the code
  • Flavor2 uses all three ProGuard rules because rules from the Release block are also applied.
Close the R8
  • You can add the following configuration to gradle.properties:
android.enableR8=false
Copy the code
Enable R8 full mode
  • R8 normal mode is compatible with ProGuard. If ProGuard has been used in the original project, directly enable R8. R8 also has full mode and is not directly compatible with ProGuard.

You can also set the following in the gradle.properties file:

android.enableR8.fullMode=true
Copy the code
  • Additional tuning capabilities make R8 behave differently than ProGuard, so you may need to add additional ProGuard rules to avoid runtime issues.
Customize the code to keep
  • In some cases, R8 is hard to judge correctly and may remove code that the application actually needs:
1. When an application calls a method through a Java Native Interface (JNI) 2. When your application queries code at runtime (e.g. using Reflection) - Reflection causes R8 to fail to recognize the entry point of the code when tracing itCopy the code
  • To fix errors and force R8 to keep some code, add a line of -keep code to the ProGuard rule file, as in
-keep public class MyClass
Copy the code
  • Or add an @keep annotation for the code you want to Keep
1. Add @keep to a class to Keep the entire class as is. 2. Add this comment to a method or field to leave the method/field (and its name) and class name unchanged. 3. This annotation is only available if you are using the AndroidX annotation library and you add the ProGuard rule file that comes with the Android Gradle plugin.Copy the code
  • To output a full report of all the rules that R8 applied when building a project, add the following code to the module’s proguard-rules.pro file:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Copy the code
Customize the resources to be reserved
  • If you have specific resources that you want to keep or discard, create an XML file containing tags in your project and specify each resource to keep in the Tools: Keep attribute and each resource to discard in the Tools: Discard attribute. Both attributes accept a comma-separated list of resource names. You can use the asterisk character as a wildcard.
  • Save this file in a project resource, for example, in res/raw/keep.xml. The build system does not package this file into the application.
<? The XML version = "1.0" encoding = "utf-8"? > <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />Copy the code
Strict reference check
  • Usually the resource reductor can accurately determine whether a resource is being used or not. However, if resources.getidentifier () is called in the code (or if any referenced library makes the call, as the AppCompat library does), this means that the code will look up the resource name based on a dynamically generated string. By default (safe reduction mode), the resource reductor takes protective action, marking all resources with a matching name format as likely to be in use and cannot be removed. The resource reductor also looks at all the string constants in the code and the various res/raw/ resources to find resource urls in a format similar to file:///android_res/drawable//ic_plus_anim_016.png. If it finds strings like this, or other strings that look like they could be used to build urls like this, it doesn’t remove them.
  • For example, the following code marks all resources prefixed with img_ as used:
val name = String.format("img_%1d", angle + 1)
val res = resources.getIdentifier(name, "drawable", packageName)
Copy the code
  • Enable strict reference checking: Set the shrinkMode in the keep.xml file to strict, so that if resources are referenced by dynamically generated strings, they must be retained manually using the Tools :keep attribute.
<? The XML version = "1.0" encoding = "utf-8"? > <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />Copy the code
Remove unused spare resources
  • Gradle resource reductor only removes resources that are not referenced by the application code. This means that it does not remove standby resources for different device configurations.
  • For example, if you are using libraries that contain language resources (such as AppCompat or Google Play services), your application will contain strings of all translated languages for the messages in those libraries. You can use the resConfigs property to remove alternate resource files that the application does not need. For example, only English and French language resources are reserved
android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}
Copy the code
Merging duplicate resources
  • By default, Gradle also merges resources with the same name (when multiple files have exactly the same resource name, type, and qualifier). This behavior is not controlled by the shrinkResources property and cannot be disabled because it is necessary to avoid errors when multiple resources match the name of the code query.
  • Gradle selects the file it thinks best of the duplicates (according to the following priority order) and passes only this one resource to AAPT for distribution in the final artifact
  • Gradle merges duplicate resources in descending order of priority: library project dependencies → master resource → build variant → Build type. If a duplicate resource exists in both the master and build variant, Gradle selects the resource in the build variant.
  • If exactly the same resources appear in the same sourceSet, Gradle cannot merge them and will issue a resource merge error, or if multiple source sets are defined in the sourceSet property of the build. Gradle file, SRC /main/res/ and SRC /main/res2/ contain exactly the same resource will also report an error.

reference

  • DX has been deprecated, please migrate to D8 asap
  • Developer. The android. Google. Cn/studio/comm…
  • Compress your application with R8
  • Developer.android.com/studio/buil…

My name is Jinyang. If you want to learn more about jinyang, please pay attention to the wechat public number “Jinyang said” to receive my latest articles