Merge "new doc about shrinking code and resources (massive re-write of proguard doc). bug: 27746083" into mnc-mr-docs

This commit is contained in:
Scott Main
2016-04-12 15:18:05 +00:00
committed by Android (Google) Code Review
2 changed files with 449 additions and 147 deletions

View File

@@ -1,192 +1,493 @@
page.title=ProGuard page.title=Shrink Your Code and Resources
parent.title=Tools parent.title=Tools
parent.link=index.html parent.link=index.html
page.metaDescription=Use ProGuard to shrink, optimize, and obfuscate your code prior to release. page.metaDescription=Make your APK file smaller and more secure by shrinking your code and resources.
@jd:body @jd:body
<div id="qv-wrapper"> <div id="qv-wrapper">
<div id="qv"> <div id="qv">
<h2>In this document</h2> <h2>In this document</h2>
<ol>
<ol> <li><a href="#shrink-code">Shrink Your Code</a>
<li><a href="#enabling-gradle">Enabling ProGuard (Gradle Builds)</a></li> <ol>
<li><a href="#keep-code">Customize which code to keep</a></li>
<li><a href="#enabling">Enabling ProGuard (Ant Builds)</a></li> <li><a href="#decode-stack-trace">Decode an obfuscated stack trace</a></li>
</ol>
<li><a href="#configuring">Configuring ProGuard</a></li> </li>
<li><a href="#shrink-resources">Shrink Your Resources</a>
<li> <ol>
<a href="#decoding">Decoding Obfuscated Stack Traces</a> <li><a href="#keep-resources">Customize which resources to keep</a></li>
<li><a href="#strict-reference-checks">Enable strict reference checks</a></li>
<ol> <li><a href="#unused-alt-resources">Remove unused alternative resources</a></li>
<li><a href="#considerations">Debugging considerations for published <li><a href="#merge-resources">Merge duplicate resources</a></li>
applications</a></li> <li><a href="#troubleshoot-resource-shrink">Troubleshoot resource shrinking</a></li>
</ol> </ol>
</li> </li>
</ol> </ol>
<h2>See also</h2> <h2>See also</h2>
<ul>
<ol>
<li> <li>
<a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard <a class="external-link"
Manual &raquo;</a> href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard
Manual</a>
</li> </li>
<li> </ul>
<a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/retrace/introduction.html">ProGuard
ReTrace Manual &raquo;</a>
</li>
</ol>
</div> </div>
</div> </div>
<p>The <a href="http://proguard.sourceforge.net">ProGuard</a> tool shrinks, optimizes, and
obfuscates your code by removing unused code and
renaming classes, fields, and methods with semantically obscure names. The result is a smaller
sized <code>.apk</code> file that is more difficult to reverse engineer. Because ProGuard makes your
application harder to reverse engineer, it is important that you use it
when your application utilizes features that are sensitive to security like when you are
<a href="{@docRoot}google/play/licensing/index.html">Licensing Your Applications</a>.</p>
<p>ProGuard is integrated into the Android build system, so you do not have to invoke it <p>To make your APK file as small as possible, you should enable shrinking for
manually. ProGuard runs only when you build your application in release mode, so you do not your code and resources in your release build. This guide describes how to do
have to deal with obfuscated code when you build your application in debug mode. both and how to specify what to keep or discard during a build.</p>
Having ProGuard run is completely optional, but highly recommended.</p>
<p>This document describes how to enable and configure ProGuard as well as use the <p>Code shrinking is available with ProGuard, which detects and removes unused
<code>retrace</code> tool to decode obfuscated stack traces.</p> classes, fields, methods, and attributes from your packaged app, including
those from included code libraries (making it a valuable tool for working
around the <a href="{@docRoot}tools/building/multidex.html">64k reference
limit</a>). ProGuard also optimizes the bytecode, removes unused code
instructions, and obfuscates the remaining classes, fields, and methods with
short names. The obfuscated code makes your APK difficult to reverse engineer,
which is especially valuable when your app uses security-sensitive features,
such as <a href="{@docRoot}google/play/licensing/overview.html">licensing
verification</a>.</p>
<p>Resource shrinking is available with the Android Plugin for Gradle, which
removes unused resources from your packaged app, including unused resources in
code libraries. It works in conjunction with code shrinking such that once
unused code has been removed, any resources no longer referenced can be safely
removed as well.</p>
<h2 id="enabling-gradle">Enabling ProGuard (Gradle Builds)</h2> <p>Features in this document depend on:</p>
<p>When you create a project in Android Studio or with the Gradle build system, the <ul>
<code>minifyEnabled</code> property in the <code>build.gradle</code> file enables and disables <li><a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools</a> 25.0.10
ProGuard for release builds. The <code>minifyEnabled</code> property is part of the or higher</li>
<code>buildTypes</code> <code>release</code> block that controls the settings applied to <li><a href="{@docRoot}tools/revisions/gradle-plugin.html">Android Plugin
release builds. Set the <code>minifyEnabled</code> property to <code>true</code> to enable for Gradle</a> 2.0.0 or higher</li>
ProGuard, as shown in this example. </p> </ul>
<pre class="no-pretty-print"> <h2 id="shrink-code">Shrink Your Code</h2>
android {
...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
</pre>
<p>The <code>getDefaultProguardFile('proguard-android.txt')</code> method obtains the default <p>To enable code shrinking with ProGuard, add <code>minifyEnabled true</code>
ProGuard settings from the Android SDK <code>tools/proguard/</code> folder. The to the appropriate build type in your <code>build.gradle</code> file.</p>
<code>proguard-android-optimize.txt</code> file is also available in this Android SDK
folder with the same rules but with optimizations enabled. ProGuard optimizations perform
analysis at the bytecode level, inside and across methods to help make your app smaller and run
faster. Android Studio adds the <code>proguard-rules.pro</code> file at the root of the module,
so you can also easily add custom ProGuard rules specific to the current module. </p>
<p>You can also add ProGuard files to the <code>getDefaultProguardFile</code> <p>Be aware that code shrinking slows down the build time, so you should avoid
directive for all release builds or as part of the <code>productFlavor</code> settings in the using it on your debug build if possible. However, it's important that you
<code>build.gradle</code> file to customize the settings applied to build variants. This example do enable code shrinking on your final APK used for testing, because it might
adds the <code>proguard-rules-new.pro</code> to the <code>proguardFiles</code> introduce bugs if you do not sufficiently <a href="#keep-code">customize which
directive and the <code>other-rules.pro</code> file to the <code>flavor2</code> product flavor. </p> code to keep</a>.</p>
<p>For example, the following snippet from a <code>build.gradle</code> file
enables code shrinking for the release build:</p>
<pre class="no-pretty-print"> <pre class="no-pretty-print">
android { android {
... buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt'),
'proguard-rules.pro</a>'
}
}
...
}
</pre>
<p class="note"><strong>Note</strong>: Android Studio disables ProGuard when
using <a href=
"{@docRoot}tools/building/building-studio.html#instant-run">Instant
Run</a>.</p>
<p>In addition to the <code>minifyEnabled</code> property, the
<code>proguardFiles</code> property defines the ProGuard rules:</p>
<ul>
<li>The <code>getDefaultProguardFile(‘proguard-android.txt')</code> method gets
the default ProGuard settings from the Android SDK <code>tools/proguard/</code>
folder.
<p><strong>Tip</strong>: For even more code shrinking, try the
<code>proguard-android-optimize.txt</code> file that's in the same location. It
includes the same ProGuard rules, but with other optimizations that perform
analysis at the bytecode level—inside and across methods—to reduce your APK
size further and help it run faster.</p>
</li>
<li>The <code>proguard-rules.pro</code> file is where you can add custom
ProGuard rules. By default, this file is located at the root of the module
(next to the <code>build.gradle</code> file).</li>
</ul>
<p>To add more ProGuard rules that are specific to each build variant, add
another <code>proguardFiles</code> property in the corresponding
<code>productFlavor</code> block. For example, the following Gradle file adds
<code>flavor2-rules.pro</code> to the <code>flavor2</code> product flavor. Now
<code>flavor2</code> uses all three ProGuard rules because those from the
<code>release</code> block are also applied.</p>
<pre class="no-pretty-print">
android {
...
buildTypes { buildTypes {
release { release {
minifyEnabled true minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro', 'proguard-rules-new.pro' 'proguard-rules.pro'</span>
} }
} }
productFlavors {
productFlavors {
flavor1 { flavor1 {
} }
flavor2 { flavor2 {
proguardFile 'other-rules.pro' proguardFile 'flavor2-rules.pro'
} }
} }
} }
</pre>
<h2 id="configuring">Configuring ProGuard</h2>
<p>For some situations, the default configurations in the ProGuard configuration file will
suffice. However, many situations are hard for ProGuard to analyze correctly and it might remove
code that it thinks is not used, but your application actually needs. Some examples include:</p>
<ul>
<li>a class that is referenced only in the <code>AndroidManifest.xml</code> file</li>
<li>a method called from JNI</li>
<li>dynamically referenced fields and methods</li>
</ul>
<p>The default ProGuard configuration file tries to cover general cases, but you might
encounter exceptions such as <code>ClassNotFoundException</code>, which happens when ProGuard
strips away an entire class that your application calls.</p>
<p>You can fix errors when ProGuard strips away your code by adding a <code>-keep</code> line in
the ProGuard configuration file. For example:</p>
<pre>
-keep public class &lt;MyClass&gt;
</pre> </pre>
<p>There are many options and considerations when using the <code>-keep</code> option, so it is <p>With each build, ProGuard outputs the following files:</p>
highly recommended that you read the <dl>
<a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard <dt><code>dump.txt</code></dt>
Manual</a> for more information about customizing your configuration file. The <dd>Describes the internal structure of all the class files in the APK.</dd>
<em>Overview of Keep options</em> and <em>Examples</em> sections are particularly helpful.
The <a href=
"http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/troubleshooting.html">Troubleshooting
</a> section of the ProGuard Manual outlines other common problems you might encounter
when your code gets stripped away.</p>
<h2 id="decoding">Decoding Obfuscated Stack Traces</h2> <dt><code>mapping.txt</code></dt>
<dd>Provides a translation between the original and obfuscated class, method, and
field names.</dd>
<p>When your obfuscated code outputs a stack trace, the method names are obfuscated, which makes <dt><code>seeds.txt</code></dt>
debugging hard, if not impossible. Fortunately, whenever ProGuard runs, it outputs a <dd>Lists the classes and members that were not obfuscated.</dd>
<code>mapping.txt</code> file, which shows you the original class, method, and field names
mapped to their obfuscated names.</p>
<p>The <code>retrace.bat</code> script on Windows or the <code>retrace.sh</code> script on Linux <dt><code>usage.txt</code></dt>
or Mac OS X can convert an obfuscated stack trace to a readable one. It is located <dd>Lists the code that was removed from the APK.</dd>
in the <code>&lt;sdk_root&gt;/tools/proguard/</code> directory. The syntax for executing the </dl>
<code>retrace</code> tool is:</p>
<pre>retrace.bat|retrace.sh [-verbose] mapping.txt [&lt;stacktrace_file&gt;]</pre>
<p>For example:</p>
<pre>retrace.bat -verbose mapping.txt obfuscated_trace.txt</pre> <p>These files are saved at
<code>&lt;module-name&gt;/build/outputs/mapping/release/</code>.</p>
<p>If you do not specify a value for <em>&lt;stacktrace_file&gt;</em>, the <code>retrace</code> tool reads
from standard input.</p>
<h3 id="considerations">Debugging considerations for published applications</h3> <h3 id="keep-code">Customize which code to keep</h3>
<p>Save the <code>mapping.txt</code> file for every release that you publish to your users. <p>For some situations, the default ProGuard configuration file
By retaining a copy of the <code>mapping.txt</code> file for each release build, (<code>proguard-android.txt</code>) is sufficient and ProGuard removes all—and
you ensure that you can debug a problem if a user encounters a bug and submits an obfuscated stack trace. only—the unused code. However, many situations are difficult for ProGuard to
A project's <code>mapping.txt</code> file is overwritten every time you do a release build, so you must be analyze correctly and it might remove code your app actually needs. Some
careful about saving the versions that you need. The file is stored in the app <code>build/outs/</code> folder. </p> examples of when it might incorrectly remove code include:</p>
<p>For example, say you publish an application and continue developing new features of <ul>
the application for a new version. You then do a release build using ProGuard soon after. The <li>When your app references a class only from the
build overwrites the previous <code>mapping.txt</code> file. A user submits a bug report <code>AndroidManifest.xml</code> file</li>
containing a stack trace from the application that is currently published. You no longer have a way <li>When your app calls a method from the Java Native Interface (JNI)</li>
of debugging the user's stack trace, because the <code>mapping.txt</code> file associated with the version <li>When your app manipulates code at runtime (such as with reflection or
on the user's device is gone. There are other situations where your <code>mapping.txt</code> file can be overwritten, so introspection)</li>
ensure that you save a copy for every release that you anticipate you have to debug.</p> </ul>
<p>How you save the <code>mapping.txt</code> files is your decision. For example, you can rename <p>Testing your app should reveal any errors caused by inappropriately removed
the files to include a version or build number, or you can version control them along with your code, but you can also inspect what code was removed by reviewing the
source code.</p> <code>usage.txt</code> output file saved in
<code>&lt;module-name&gt;/build/outputs/mapping/release/</code>.</p>
<p>To fix errors and force ProGuard to keep certain code, add a <code><a
href="https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/usage.html"
>-keep</a></code> line in the ProGuard configuration file. For example:</p>
<pre>
-keep public class MyClass
</pre>
<p>Alternatively, you can add the <code><a href=
"{@docRoot}reference/android/support/annotation/Keep.html">@Keep</a></code>
annotation to the code you want to keep. Adding <code>@Keep</code> on a class
keeps the entire class as-is. Adding it on a method or field will keep the
method/field (and it's name) as well as the class name intact. Note that this
annotation is available only when using the <a href=
"{@docRoot}tools/support-library/features.html#annotations">Annotations Support
Library</a>.</p>
<p>There are many considerations you should make when using the
<code>-keep</code> option; for more information about customizing your
configuration file, read the <a href=
"http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">
ProGuard Manual</a>. The <a href=
"http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/troubleshooting.html">
Troubleshooting</a> section outlines other common problems you might encounter
when your code gets stripped away.</p>
<h3 id="decode-stack-trace">Decode an obfuscated stack trace</h3>
<p>After ProGuard shrinks your code, reading a stack trace is difficult (if not
impossible) because the method names are obfuscated. Fortunately, ProGuard
creates a <code>mapping.txt</code> file each time it runs, which shows the
original class, method, and field names mapped to the obfuscated names.
ProGuard saves the file in the app
<code>&lt;module-name&gt;/build/outputs/mapping/release/</code> directory.</p>
<p>Be aware that the <code>mapping.txt</code> file is overwritten every time
you create a release build with ProGuard, so you must carefully save a copy
each time you publish a new release. By retaining a copy of the
<code>mapping.txt</code> file for each release build, you'll be able to debug a
problem if a user submits an obfuscated stack trace from an older version of
your app.</p>
<p>When publishing your app on Google Play, you can upload the
<code>mapping.txt</code> file for each version of your APK. Then Google Play
will deobfuscate incoming stack traces from user-reported issues so you can
review them in the Google Play Developer Console. For more information, see the
Help Center article about how to <a href=
"https://support.google.com/googleplay/android-developer/answer/6295281">deobfuscate
crash stack traces</a>.</p>
<p>To convert an obfuscated stack trace to a readable one yourself, use the
<code>retrace</code> script (<code>retrace.bat</code> on Windows;
<code>retrace.sh</code> on Mac/Linux). It is located in the
<code>&lt;sdk-root&gt;/tools/proguard/</code> directory. The script takes the
<code>mapping.txt</code> file and your stack trace, producing a new, readable
stack trace. The syntax for using the retrace tool is:</p>
<pre class="no-pretty-print">
retrace.bat|retrace.sh [-verbose] mapping.txt [&lt;stacktrace_file&gt;]
</pre>
<p>For example:</p>
<pre class="no-pretty-print">
retrace.bat -verbose mapping.txt obfuscated_trace.txt
</pre>
<p>If you do not specify the stack trace file, the retrace tool reads from
standard input.</p>
<h2 id="shrink-resources">Shrink Your Resources</h2>
<p>Resource 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.</p>
<p>To enable resource shrinking, set the <code>shrinkResources</code> property
to <code>true</code> in your <code>build.gradle</code> file (alongside
<code>minifyEnabled</code> for code shrinking). For example:</p>
<pre class="no-pretty-print">
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
</pre>
<p>If you haven't already built your app using <code>minifyEnabled</code> for
code shrinking, then try that before enabling <code>shrinkResources</code>,
because you might need to edit your <code>proguard-rules.pro</code> file to
keep classes or methods that are created or invoked dynamically before you
start removing resources.</p>
<p class="note"><strong>Note</strong>: The resource shrinker currently does not
remove resources defined in a <code>values/</code> folder (such as strings,
dimensions, styles, and colors). This is because the Android Asset Packaging
Tool (AAPT) does not allow the Gradle Plugin to specify predefined versions for
resources. For details, see <a href=
"https://code.google.com/p/android/issues/detail?id=70869">issue 70869</a>.</p>
<h3 id="keep-resources">Customize which resources to keep</h3>
<p>If there are specific resources you wish to keep or discard, create an XML
file in your project with a <code>&lt;resources&gt;</code> tag and specify each
resource to keep in the <code>tools:keep</code> attribute and each resource to
discard in the <code>tools:discard</code> attribute. Both attributes accept a
comma-separated list of resource names. You can use the asterisk character as a
wild card.</p>
<p>For example:</p>
<pre>
&lt;?xml version=1.0" encoding="utf-8"?&gt;
&lt;resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="&#64;layout/l_used*_c,&#64;layout/l_used_a,&#64;layout/l_used_b*"
tools:discard="&#64;layout/unused2" /&gt;
</pre>
<p>Save this file in your project resources, for example, at
<code>res/raw/keep.xml</code>. The build does not package this file into your
APK.</p>
<p>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 <code>keep.xml</code> file for each build variant when
you know that a given resource appears to be used in code (and therefore not
removed by the shrinker) but you know it actually won't be used for the given
build variant.</p>
<h3 id="strict-reference-checks">Enable strict reference checks</h3>
<p>Normally, the resource shrinker can accurately determine whether a resource
is used. However, if your code makes a call to {@link
android.content.res.Resources#getIdentifier(String,String,String)
Resources.getIdentifier()} (or if any of your libraries do that—the <a href=
"{@docRoot}tools/support-library/features.html#v7-appcompat">AppCompat</a>
library does), that means your code is looking up resource names based on
dynamically-generated strings. When you do this, the resource shrinker behaves
defensively by default and marks all resources with a matching name format as
potentially used and unavailable for removal.</p>
<p>For example, the following code causes all resources with the
<code>img_</code> prefix to be marked as used.</p>
<pre>
String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());
</pre>
<p>The resource shrinker also looks through all the string constants in your
code, as well as various <code>res/raw/</code> resources, looking for resource
URLs in a format similar to
<code>file:///android_res/drawable//ic_plus_anim_016.png</code>. If it finds
strings like this or others that look like they could be used to construct URLs
like this, it doesn't remove them.</p>
<p>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 <code>shrinkMode</code> to <code>strict</code> in the
<code>keep.xml</code> file, as follows:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;resources xmlns:tools="http://schemas.android.com/tools"
tools:shrinkMode="strict" /&gt;
</pre>
<p>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 <code>tools:keep</code> attribute.</p>
<h3 id="unused-alt-resources">Remove unused alternative resources</h3>
<p>The Gradle resource shrinker removes only resources that are not referenced
by your app code, which means it will not remove <a href=
"{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
alternative resources</a> for different device configurations. If necessary,
you can use the Android Gradle plugin's <code>resConfigs</code> property to
remove alternative resource files that your app does not need.</p>
<p>For example, if you are using a library that includes language resources
(such as AppCompat or Google Play Services), then your APK 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 <code>resConfig</code> property. Any resources for
languages not specified are removed.</p>
<p>The following snippet shows how to limit your language resources to just
English and French:</p>
<pre class="no-pretty-print">
android {
defaultConfig {
...
resConfigs "en", "fr"
}
}
</pre>
<p>To customize which screen density or ABI resources to include in your APK,
instead use <a href=
"http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits">APK
splits</a> to build different APKs for different devices.</p>
<h3 id="merge-resources">Merge duplicate resources</h3>
<p>By 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 <code>shrinkResources</code> property and
cannot be disabled, because it is necessary to avoid errors when multiple
resources match the name your code is looking up.</p>
<p>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
APK file.</p>
<p>Gradle looks for duplicate resources in the following locations:</p>
<ul>
<li>The main resources, associated with the main source set, generally
located in <code>src/main/res/</code>.</li>
<li>The variant overlays, from the build type and build flavors.</li>
<li>The library project dependencies.</li>
</ul>
<p>Gradle merges duplicate resources in the following cascading priority order:</p>
<p>Dependencies → Main → Build flavor → Build type</p>
<p>For example, if a duplicate resource appears in both your main resources and
a build flavor, Gradle selects the one in the build flavor.</p>
<p>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 <code>sourceSet</code> property of your
<code>build.gradle</code> file—for example if both <code>src/main/res/</code>
and <code>src/main/res2/</code> contain identical resources.</p>
<h3 id="troubleshoot-resource-shrink">Troubleshoot resource shrinking</h3>
<p>When you shrink resources, the Gradle Console shows a summary of the
resources that it removed from the app package. For example:</p>
<pre class="no-pretty-print">
:android:shrinkDebugResources
Removed unused resources: Binary resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
</pre>
<p>Gradle also creates a diagnostic file named <code>resources.txt</code> in
<code>&lt;module-name&gt;/build/outputs/mapping/release/</code> (the same
folder as ProGuard's output files). This file includes details such as which
resources reference other resources and which resources are used or
removed.</p>
<p>For example, to find out why <code>&#64;drawable/ic_plus_anim_016</code> is
still in your APK, open the <code>resources.txt</code> file and search for that
file name. You might find that it's referenced from another resource, as
follows:</p>
<pre class="no-pretty-print">
16:25:48.005 [QUIET] [system.out] &#64;drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] &#64;drawable/ic_plus_anim_016
</pre>
<p>You now need to know why <code>&#64;drawable/add_schedule_fab_icon_anim</code>
is reachable—and if you search upwards you'll find that resource is listed
under "The root reachable resources are:". This means there is a code reference
to <code>add_schedule_fab_icon_anim</code> (that is, its R.drawable ID was
found in the reachable code).</p>
<p>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:</p>
<pre class="no-pretty-print">
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because it format-string matches string pool constant ic_plus_anim_%1$d.
</pre>
<p>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
<code>tools:discard</code> attribute to inform the build system to remove it,
as described in the section about how to <a href="#keep-resources"
>customize which resources to keep</a>.</p>

View File

@@ -96,6 +96,8 @@
<span class="en">Improving Your Code with lint</span></a></li> <span class="en">Improving Your Code with lint</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/annotations.html"> <li><a href="<?cs var:toroot ?>tools/debugging/annotations.html">
<span class="en">Improving Code Inspection with Annotations</span></a></li> <span class="en">Improving Code Inspection with Annotations</span></a></li>
<li><a href="<?cs var:toroot ?>tools/help/proguard.html">
<span class="en">Shrink Your Code and Resources</span></a></li>
<li><a href="<?cs var:toroot ?>tools/help/app-link-indexing.html"> <li><a href="<?cs var:toroot ?>tools/help/app-link-indexing.html">
<span class="en">Supporting URLs and App Indexing in Android Studio</span></a></li> <span class="en">Supporting URLs and App Indexing in Android Studio</span></a></li>
</ul> </ul>
@@ -226,7 +228,6 @@ class="en">Tools Help</span></a></div>
</ul> </ul>
</li> </li>
<li><a href="<?cs var:toroot ?>tools/help/mksdcard.html">mksdcard</a></li> <li><a href="<?cs var:toroot ?>tools/help/mksdcard.html">mksdcard</a></li>
<li><a href="<?cs var:toroot ?>tools/help/proguard.html" zh-cn-lang="ProGuard">ProGuard</a></li>
<li><a href="<?cs var:toroot ?>tools/help/gltracer.html">Tracer for OpenGL ES</a></li> <li><a href="<?cs var:toroot ?>tools/help/gltracer.html">Tracer for OpenGL ES</a></li>