The ancients learned without exhaustion, young time old beginning.

How does ProGuard relate to R8?

When building a project using the Android Gradle plug-in version 3.4.0 or higher, the plug-in no longer uses ProGuard to perform compile-time code optimizations, but instead works with the R8 compiler to handle compile-time tasks.

How does the R8 compiler optimize applications?

  • Code reduction (tree shaker) : Detect and safely remove unused classes, fields, methods, and properties from applications and their library dependencies (this makes it a very useful tool for getting around the 64K reference limit). For example, if you only use a few apis for a library dependency, the reduction feature can identify library code that is “unused” by your application and remove only that code from your application.
  • Resource reduction: Remove unused resources from encapsulated applications, including unused resources from application library dependencies. This feature can be used in conjunction with code reduction, so that when you remove code that is not being used, you can safely remove all resources that are no longer referenced.
  • Obfuscation handling: Shorten the names of classes and members to reduce the size of DEX files.
  • To optimize the: Review and rewrite the code to further reduce the application’s DEX file size. For example, if R8 detects that the given if/else statement was never usedelse {}Branches are removedelse {}Branch code.

Field experience

(1) Reduction – confusion – optimization

Enable reduction, obfuscation, and optimization. Android Studio disables R8 by default. Therefore, it is a good idea to enable these compile-time tasks when building the final version of the application (that is, the version tested before the application is released). To enable reduction, obfuscation handling, and optimization, add the following code to your project-level build.gradle file:

Android {buildTypes {release {// Enable code reduction, obfuscation handling and optimization minifyEnabled true // Enable resource file reduction, optimization shrinkResources True ProguardFiles getDefaultProguardFile(' proguard-Android-optimize.txt '), 'proguard-rules.pro' } } ... }Copy the code

(2) R8 configuration file

R8 uses ProGuard rules files to modify its default behavior and better understand the structure of the application, such as classes that act as entry points to the application code. While you can modify some of these rule files, some rules may be automatically generated by compile-time tools (such as AAPT2) or inherited from applied library dependencies. The following table describes the source of the ProGuard rule files used by R8:

source location instructions
Android Studio /proguard-rules.pro When you create a new module using Android Studio, the IDE is created in the root directory of the moduleproguard-rules.proFile.

By default, no rules are applied to this file. Therefore, add your own ProGuard rules here, such as your custom reservation rules.
Android Gradle plug-in Generated by the Android Gradle plugin at compile time The Android Gradle plugin is generatedproguard-android-optimize.txt(contains rules that are useful for most Android projects) and enable@Keep*The comments.

By default, when creating a new module using Android Studio, the module levelbuild.gradleThe rule file will incorporate this rule file into your release.

Note: Although the Android Gradle plugin includes additional predefined ProGuard rule files, it is recommended that you use proguard-Android-optimize.txt.
Library dependencies AAR library: / proguard. TXT

A JAR library: / meta-inf/proguard /
If an AAR library is published using its own ProGuard rules file, and you include the AAR library as a compile-time dependency in the project, R8 automatically applies its rules when compiling the project.

If the AAR library requires some reserved rules to function properly, it is useful to use the rules file that comes with the library. That is, the library developer has performed the troubleshooting steps for you.

Note, however, that 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 optimization, that rule deactivates optimization for the entire project.
Android Asset Packaging Tool 2 (AAPT2) Using minifyEnabled true after building the project: the module – dir > / build/intermediates/proguard – rules/debug/aapt_rules. TXT AAPT2 generate retention rules based on references to classes, layouts, and other application resources in the application list. For example, AAPT2 add a reservation rule for each Activity that you register as an entry point in the application manifest.
Custom configuration files By default, when you create a new module using Android Studio, the IDE creates/ProGuard-rules.pro so that you can add your own rules. You can add additional configurations, which R8 applies at compile time.

If the minifyEnabled attribute is set to true, R8 consolidates the rules from all of the above available sources. Keep this in mind when troubleshooting R8 problems, because other compile-time dependencies, such as library dependencies, may introduce changes in R8 behavior that you don’t know about. 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

(3) Add other configurations

When you create a new project or module using Android Studio, the IDE creates a/ProGuard-rules.pro file for you to add your own rules. In addition, you can add additional rules from other files by adding the corresponding files to the proguardFiles property in the module’s build.gradle file.

android {
        buildTypes {
            release {
                minifyEnabled true
                shrinkResources true
                proguardFiles getDefaultProguardFile(
                        'proguard-android-optimize.txt'),
                        'proguard-rules.pro', 'media-proguard-rules.pro', 'video-proguard-rules.pro'
            }
        }
        ...
    } 
Copy the code

(4) Shorten the code

  • If the minifyEnabled attribute is set to true, R8 code reduction is enabled by default.
  • Code reduction (also known as “tree shaking”) is the process of removing code that R8 determines is not needed at run time. This process can greatly reduce the size of your application, for example, if your application contains many library dependencies but uses only a fraction of their functionality.
  • To shrink the application code, R8 first identifies all entry points of the application code based on the combined set of configuration files. These entry points include all the classes that the Android platform can use to open an application’s activities or services. Starting at each entry point, R8 examines the application’s code to build a chart listing all the methods, member variables, and other classes that the application might access at runtime. Code that is not associated with this diagram will be considered unexecutable and may be removed from the application.
  • R8 through the project’s R8 configuration file-keepRules determine entry points. That is, the retention rule specifies classes that R8 should not discard when scaling down the application, and R8 sees these classes as possible entry points for the application. The Android Gradle plug-in and AAPT2 automatically generate the retention rules you need for most application projects, such as your application’s activities, views, and services.

(5) Customize the code to be retained

In most cases, the default ProGuard rules file (proguard-Android-optimize.txt) is sufficient for R8 to remove only unused code. In some cases, however, R8 is hard to make the right call and may remove code that your application actually needs. Here are a few examples of situations in which it might incorrectly remove code:

  • When your application invokes methods through the Java Native Interface (JNI)
  • When your application queries code at run time (such as using reflection)

Testing your application should be able to detect errors caused by incorrectly removing code, but you can also check what code was removed by generating a report of removed code. To fix the bug and force R8 to keep some code, add -keep to the ProGuard rules file. Such as:

-keep public class MyClass
Copy the code

Alternatively, you can add @keep annotations to the code you want to Keep. Adding @keep to the class preserves the entire class as is. Adding this annotation to a method or field leaves the method/field (and its name) as well as the class name unchanged. Note that this comment is only available if you use the AndroidX comment library and you add the ProGuard rules file that comes with the Android Gradle plug-in.

(6) Reduce resources

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 you add a code base that contains the resources. You must remove unused library code, making the library resource unreferenced and thus removable by the resource reductor.

 shrinkResources true
Copy the code

(7) Customize the resources to be retained

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.

<? 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

Save this file in a project resource, for example, res/raw/keep.xml. The build system does not package this file into APK.

(8) Enable strict reference check

In general, the resource reductor can accurately determine whether a resource is being used. However, if your code calls Resources.getidentifier () (or if any of your libraries makes this call, as the AppCompat library does), it means that your code will query for resource names based on dynamically generated strings. When you enable strict reference checking, the reductor takes protective action by default, marking all resources with matching name formats as likely to be in use and unable to be removed. For example, the following code marks all resources with img_ prefix as used.

  val name = String.format("img_%1d", angle + 1)
  val res = resources.getIdentifier(name, "drawable", packageName)
Copy the code

Here are some examples of the safe reduction mode enabled by default. However, you can disable this “nip in the bud” processing by specifying that the resource reductor only holds the resources you are sure to use. To do this, you can set shrinkMode in the keep.xml file to strict, as shown below:

<? The XML version = "1.0" encoding = "utf-8"? > <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />Copy the code

If you do enable strict reduction mode, and your code also references resources through dynamically generated strings (as shown above), you must use the Tools: Keep attribute to manually reserve these resources.

(9) Remove unused spare resources

Gradle resource reductor only removes resources that are not referenced by your application code, which means that it does not remove alternate resources for different device configurations. If necessary, you can use the resConfigs property of the Android Gradle plugin to remove backup resource files that are not needed by your application. The following code snippet shows how to set up only English and French language resources:

android {
        defaultConfig {
            ...
            resConfigs "en", "fr"
        }
    }
Copy the code

(10) Merge duplicate resources

By default, Gradle also merges resources with the same name, such as drawable objects that may reside in different resource folders. 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. A resource merge occurs only if two or more files have exactly the same resource name, type, and qualifier. Gradle selects the file it thinks best of the duplicates (in the following order of precedence) and passes only this one resource to AAPT for distribution in APK files. Gradle looks for duplicate resources in the following locations:

  • The primary resource associated with the primary source set is typically in SRC /main/res/.
  • Variant overlay from version types and version variants.
  • Library project dependencies.

Gradle merges duplicate resources in descending order of priority: dependencies → main resource → version variant → version type

If exactly the same resources appear in the same source set, Gradle cannot merge them and will issue a resource merge error. This can happen if you define multiple source sets in the sourceSet property of your build.gradle file. For example, this could happen if SRC /main/res/ and SRC /main/res2/ contain exactly the same resources.

(11) The code is obfuscated

The purpose of obfuscation is to reduce the size of an application by shortening the names of its classes, methods, and fields.

Obfuscation does not remove code from an application, but it can significantly reduce the size of an application if its DEX file indexes many classes, methods, and fields. In addition, if your code depends on the predictable naming of applied methods and classes (for example, when using reflection), you should treat the corresponding signatures as entry points and specify retention rules for them. These retention rules tell R8 not only to keep the code in the application’s final DEX, but also to keep its original name.

(12) Decode the confused stack trace

When R8 obfuscates your code, it makes it much harder to understand the stack traces, because the names of classes and methods may have changed. In addition to renaming, R8 can also change the line number in the stack trace to further reduce the size when writing DEX files. Fortunately, R8 creates a mapping.txt file each time it runs that lists the obliquated class, method, and field names mapped to the original names. This mapping file also contains information for mapping line numbers back to the original source file line numbers. R8 will store this file in /build/outputs/mapping//.

Note: The mapping.txt file generated by R8 is overwritten every time you build a project, so be sure to save a copy of this file every time you release a new version. By keeping a copy of the mapping.txt file for each release, you can debug problems when users submit obfuscated stack traces from older applications.

(13) Code optimization

To further shrink applications, R8 examines code at a deeper level to remove more unused code, or if possible, rewrite code to make it more concise. Here are a few examples of such optimizations:

  • If your code never takes the given if/else statementelse {}The branch, R8 might be removedelse {}Branch code.
  • If your code calls a method in only one place, R8 might remove the method and embed it in that one call point.
  • If R8 determines that a class has only one unique subclass and the class itself is not instantiated (for example, an abstract base class used only by a concrete implementation class), it can merge the two classes together and remove a class from the application.
  • For more details, read Jake Wharton’s blog post on R8 optimization.

R8 does not allow you to disable or enable discrete optimization, nor does it allow you to modify the behavior of optimization. In fact, R8 ignores all ProGuard rules that attempt to modify default optimization behavior, such as -Optimizations and -OptimizationPasses. This limitation is important because as R8 continues to improve, maintaining standard optimization behavior helps the Android Studio team easily troubleshoot and resolve any issues you may encounter.

(14) Enable more aggressive optimizations

R8 includes an additional set of optimization features that are disabled by default. You can enable these additional optimizations by adding the following code to your project’s gradle.properties file:

android.enableR8.fullMode=true
Copy the code

These additional optimizations make R8 behave differently than ProGuard, so you may need to add additional ProGuard rules to avoid runtime problems. For example, suppose your code references a class through the Java Reflection API. By default, R8 assumes that you intend to examine and manipulate objects of the class at run time (even if your code doesn’t actually do that), so it automatically preserves the class and its static initializer. However, R8 does not make this assumption when using “full mode,” and if R8 determines that your code never uses the class at run time, it removes the class from the application’s final DEX. That is, if you want to preserve the class and its static initializer, you need to add the corresponding reservation rules to the rules file.

(15) Generate code report for removal/retention

Generate reports of removed (or retained) code. To facilitate troubleshooting for specific R8 problems, it is recommended that you review reports of all code that R8 has removed from your application. Add -printUsage

/usage.txt to your custom rules file for each module for which you want to generate this report. When you build an application with R8 enabled, R8 outputs a report with the path and file name you specify. You can also view it in the following path:

(16) Check the resource reduction problem

In Gradle/build/outputs/mapping/release/(ProGuard output file in folder) to create a named resources. The diagnosis of TXT file. This file contains details such as which resources reference other resources, which resources are in use, and which resources have been removed.

Check out your own R8

Xiaobian extension links

  • SamplePop code download
  • Android Performance Optimization family Bucket

Refer to the link

  • This is the first article that should be read
  • Google Play -> de-obfuscating crashed stack tracking
  • Jake Wharton -> R8 optimized blog post

Look back at a smile 100 mei health, liugong fandai no color

❤ ❤ than heart