To make your app as small as possible, you should enable shrinking in your release build to remove unused code and resources. When enabling shrinking, you also benefit from obfuscation, which shortens the names of your app’s classes and members, and optimization, which applies more aggressive strategies to further reduce the size of your app. This page describes how R8 performs these compile-time tasks for your project and how you can customize them. Show
When you build your project using Android Gradle plugin 3.4.0 or higher, the plugin no longer uses ProGuard to perform compile-time code optimization. Instead, the plugin works with the R8 compiler to handle the following compile-time tasks:
When building the release version of your app, by default, R8 automatically performs the compile-time tasks described above for you. However, you can disable certain tasks or customize R8’s behavior through ProGuard rules files. In fact, R8 works with all of your existing ProGuard rules files, so updating the Android Gradle plugin to use R8 should not require you to change your existing rules. Enable shrinking, obfuscation, and optimizationWhen you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, R8 is the default compiler that converts your project’s Java bytecode into the DEX format that runs on the Android platform. However, when you create a new project using Android Studio, shrinking, obfuscation, and code optimization is not enabled by default. That’s because these compile-time optimizations increase the build time of your project and might introduce bugs if you do not sufficiently customize which code to keep. So, it’s best to enable these compile-time tasks when building the final version of your app that you test prior to
publishing. To enable shrinking, obfuscation, and optimization, include the following in your project-level
R8 configuration filesR8 uses ProGuard rules files to modify its default behavior and better understand your app’s structure, such as the classes that serve as entry points into your app’s code. Although you can modify some of these rules files, some rules may be generated automatically by compile-time tools, such as AAPT2, or inherited from your app’s library dependencies. The table below describes the sources of ProGuard rules files that R8 uses.
When you set the To output a full report of all the rules that R8 applies when
building your project, include the following in your module’s
Include additional configurationsWhen you create a new project or module using Android Studio, the IDE creates a For example, you can add rules that
are specific to each build variant by adding another
Shrink your codeCode shrinking with R8 is enabled by default when you set the Code shrinking (also known as tree shaking), is the process of removing code that R8 determines is not required at runtime. This process can greatly reduce your app's size if, for example, your app includes many library dependencies but utilizes only a small part of their functionality. To shrink your app’s code, R8 first determines all entry points into your app’s code based on the combined set of configuration files. These entry points include all classes that the Android platform may use to open your app’s Activities or services. Starting from each entry point, R8 inspects your app’s code to build a graph of all methods, member variables, and other classes that your app might access at runtime. Code that is not connected to that graph is considered unreachable and may be removed from the app. Figure 1 shows an app with a runtime library dependency. While inspecting the app’s code, R8 determines that methods Figure 1. At compile-time, R8 builds a graph based on your project's combined keep rules to determine unreachable code. R8 determines entry points through If instead you are interested only in reducing the size of your app’s resources, skip to the section about how to shrink your resources. Customize which code to keepFor most situations, the default ProGuard rules file (
Testing your app should reveal any errors caused by inappropriately removed code, but you can also inspect what code was removed by generating a report of removed code. To fix errors and force R8 to keep certain code, add a
Alternatively, you can add the There are many considerations you should make when using the Strip native librariesBy default, native code libraries are stripped in release builds of your app. This stripping consists of removing the symbol table and debugging information contained in any native libraries used by your app. Stripping native code libraries results in significant size savings; however, it's impossible to diagnose crashes on the Google Play Console due to the missing information (such as class and function names). Native crash supportThe Google Play Console reports native crashes under Android vitals. With a few steps, you can generate and upload a native debug symbols file for your app. This file enables symbolicated native crash stack traces (that include class and function names) in Android vitals to help you debug your app in production. These steps vary depending on the version of the Android Gradle plugin used in your project and the build output of your project. Android Gradle plugin version 4.1 or laterIf your project builds an Android App Bundle, you can automatically include the native debug symbols file in it. To include this file in release builds, add the following to your app's
Select the debug symbol level from the following:
If your project builds an APK, use the
Android Gradle plugin version 4.0 or earlier (and other build systems)As part of the build process, the Android Gradle plugin keeps a copy of the unstripped libraries in a project directory. This directory structure is similar to the following:
Shrink your resourcesResource shrinking works only in conjunction with code shrinking. After the code shrinker removes all unused code, the resource shrinker can identify which resources the app still uses. This is especially true when you add code libraries that include resources—you must remove unused library code so the library resources become unreferenced and, thus, removable by the resource shrinker. To enable resource shrinking, set the
If you haven't already built your app using Customize which resources to keepIf there are specific resources you wish to keep or discard, create an XML file in your project with a For example: <?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" /> Save this file in your project resources, for example, at Specifying which resources to discard might seem silly when you could instead delete them, but this can be useful when using build variants. For example, you might put all your resources into the common project directory, then create a different Enable strict reference checksNormally, the resource shrinker can accurately determine
whether a resource is used. However, if your code makes a call to For example, the following code causes all resources with the
The resource shrinker also looks through all the string constants in your code, as well as various These are examples of the safe shrinking mode that is enabled by default. You can, however, turn off this "better safe than sorry" handling, and specify that the resource shrinker keep only resources that it's certain are used. To do this, set <?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" /> If you do enable strict shrinking mode and your code also references resources with
dynamically-generated strings, as shown above, then you must manually keep those resources using the Remove unused alternative resourcesThe Gradle resource shrinker removes only resources that are not referenced by your app code, which means it will not remove
alternative resources for different device configurations. If necessary, you can use the Android Gradle plugin's For example, if you are using a library that includes language resources (such as AppCompat or Google Play Services), then your app includes all translated language strings for the messages in those libraries whether the rest of your app is translated to the same languages or not. If you'd
like to keep only the languages that your app officially supports, you can specify those languages using the The following snippet shows how to limit your language resources to just English and French:
When releasing an app using the Android App Bundle format, by default only languages configured on a user's device are downloaded when installing the app. Similarly, only resources matching the device's screen density, and native libraries matching the device's ABI are included in the download. For more information refer to the Android App Bundle configuration. For legacy apps releasing with APKs (created before August 2021), you can customize which screen density or ABI resources to include in your APK by building multiple APKs that each target a different device configuration. Merge duplicate resourcesBy default, Gradle also merges identically named resources, such as drawables with the same name that might be in different resource folders. This behavior is
not controlled by the Resource merging occurs only when two or more files share an identical resource name, type, and qualifier. Gradle selects which file it considers to be the best choice among the duplicates (based on a priority order described below) and passes only that one resource to the AAPT for distribution in the final artifact. Gradle looks for duplicate resources in the following locations:
Gradle merges duplicate resources in the following cascading priority order: Dependencies → Main → Build flavor → Build type For example, if a duplicate resource appears in both your main resources and a build flavor, Gradle selects the one in the build flavor. If identical resources appear in the same source set, Gradle cannot merge them and emits a resource merge error. This can happen if you define multiple source sets in the Obfuscate your codeThe purpose of obfuscation is to reduce your app size by shortening the names of your app’s classes, methods, and fields. The following is an example of obfuscation using R8:
While obfuscation does not remove code from your app, significant size savings can be seen in apps with DEX files that index many classes, methods, and fields. However, as obfuscation renames different parts of your code, certain tasks, such as inspecting stack traces, require additional tools. To understand your stacktrace after obfuscation, read the section about how to decode an obfuscated stack trace. Additionally, if your code relies on predictable naming for your app’s methods and classes—when using reflection, for example, you should treat those signatures as entry points and specify keep rules for them, as described in the section about how to customize which code to keep. Those keep rules tell R8 to not only keep that code in your app’s final DEX but also retain its original naming. Decode an obfuscated stack traceAfter R8 obfuscates your code, understanding a stack trace is difficult (if not impossible) because names of classes and methods might have been changed. To obtain the original stack trace you should retrace the stack trace. Code optimizationIn order to shrink your app even further, R8 inspects your code at a deeper level to remove more unused code or, where possible, rewrite your code to make it less verbose. The following are a few examples of such optimizations:
R8 does not allow you to disable or enable discrete optimizations, or modify the behavior of an optimization. In fact, R8 ignores any ProGuard rules that attempt to modify default optimizations, such as Note that enabling optimization will change the stack traces for your application. For example, inlining will remove stack frames. See the section on retracing to learn how to obtain the original stack traces. Enable more aggressive optimizationsR8 includes
a set of additional optimizations that are not enabled by default. You can enable these additional optimizations by including the following in your project’s
Because the additional optimizations make R8 behave differently from ProGuard, they may require you to include additional ProGuard rules to avoid runtime issues. For example, say that your code references a class through the Java Reflection API. By default, R8 assumes that you intend to examine and manipulate objects of that class at runtime—even if your code actually does not—and it automatically keeps the class and its static initializer. However, when using “full mode”, R8 does not make this assumption and, if R8 asserts that your code otherwise never uses the class at runtime, it removes the class from your app’s final DEX. That is, if you want to keep the class and its static initializer, you need to include a keep rule in your rules file to do that. If you encounter any issues while using R8’s “full mode”, refer to the R8 FAQ page for a possible solution. If you are unable to resolve the issue, please report a bug. Retracing stacktracesCode processed by R8 is changed in various ways that can make stack traces harder to understand because the stack traces won't exactly correspond to the source code. This can be the case for changes to the line numbers when debugging information is not kept. It can be due to optimizations such as inlining and outlining. The largest contributor is obfuscation where even the classes and methods will change names. To recover the original stack trace, R8 provides the retrace command-line tool, which is bundled with the command-line tools package. To support retracing of your application's stack traces, you should ensure the build retains sufficient information to retrace with by adding the following rules to your module's
The R8 creates a When publishing your app on Google Play, you can upload the Troubleshoot with R8This section describes some strategies for troubleshooting issues when enabling shrinking, obfuscation, and optimization using R8. If you do not find a solution to your issue below, also read the R8 FAQ page and ProGuard’s troubleshooting guide. Generate a report of removed (or kept) codeTo help you troubleshoot certain R8 issues, it may be useful to see a report of all the code that R8 removed from your
app. For each module for which you want to generate this report, add
If instead you want to see a report of the entry points that R8 determines from your project’s keep rules , include
Troubleshoot resource shrinkingWhen you shrink resources, the Build window shows a summary of the resources that are removed from the app. (You need to first click Toggle view on the left side of the window to display detailed text output from Gradle.) For example:
Gradle also creates a diagnostic file named For example, to find out why
You now need to know why If you are not using strict checking, resource IDs can be marked as reachable if there are string constants that look like they might be used to construct resource names for dynamically loaded resources. In that case, if you search the build output for the resource name, you might find a message like this:
If you see one of these strings and you are certain
that the string is not being used to load the given resource dynamically, you can use the What type of structure is usually used to organize folders in a file system?Hierarchical File Structure
All files in the UNIX file system are organized in a multi-leveled hierarchy called a directory tree. A family tree is an example of a hierarchical structure that represents how the UNIX file system is organized.
Which of the following is a database of information about the Windows operating system including customize settings and software installation?In other words, the registry or Windows Registry contains information, settings, options, and other values for programs and hardware installed on all versions of Microsoft Windows operating systems.
What command line utility can you use in Linux to monitor paging?The vmstat command is a useful tool that reports virtual memory statistics. vmstat provides general information about processes, memory, paging, block IO, traps, and CPU activity.
Which of the following file attributes tells the Windows operating system to backup the file?For example, IBM compatible computers running MS-DOS or Microsoft Windows have capabilities of having read, archive, system, and hidden attributes. Read-only - Allows a file to be read, but nothing can be written to the file or changed. Archive - Tells Windows Backup to back up the file.
|