diff --git a/docs/html/tools/help/proguard.jd b/docs/html/tools/help/proguard.jd index e26aca0e823ba..b38aba67b2149 100755 --- a/docs/html/tools/help/proguard.jd +++ b/docs/html/tools/help/proguard.jd @@ -1,192 +1,493 @@ -page.title=ProGuard +page.title=Shrink Your Code and Resources parent.title=Tools 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

In this document

- -
    -
  1. Enabling ProGuard (Gradle Builds)
  2. - -
  3. Enabling ProGuard (Ant Builds)
  4. - -
  5. Configuring ProGuard
  6. - -
  7. - Decoding Obfuscated Stack Traces - -
      -
    1. Debugging considerations for published - applications
    2. -
    -
  8. -
+
    +
  1. Shrink Your Code +
      +
    1. Customize which code to keep
    2. +
    3. Decode an obfuscated stack trace
    4. +
    +
  2. +
  3. Shrink Your Resources +
      +
    1. Customize which resources to keep
    2. +
    3. Enable strict reference checks
    4. +
    5. Remove unused alternative resources
    6. +
    7. Merge duplicate resources
    8. +
    9. Troubleshoot resource shrinking
    10. +
    +
  4. +

See also

- -
    +
+
- -

The ProGuard 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 .apk 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 - Licensing Your Applications.

-

ProGuard is integrated into the Android build system, so you do not have to invoke it - manually. ProGuard runs only when you build your application in release mode, so you do not - have to deal with obfuscated code when you build your application in debug mode. - Having ProGuard run is completely optional, but highly recommended.

+

To make your APK file as small as possible, you should enable shrinking for +your code and resources in your release build. This guide describes how to do +both and how to specify what to keep or discard during a build.

-

This document describes how to enable and configure ProGuard as well as use the - retrace tool to decode obfuscated stack traces.

+

Code shrinking is available with ProGuard, which detects and removes unused +classes, fields, methods, and attributes from your packaged app, including +those from included code libraries (making it a valuable tool for working +around the 64k reference +limit). 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 licensing +verification.

+ +

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.

-

Enabling ProGuard (Gradle Builds)

-

When you create a project in Android Studio or with the Gradle build system, the - minifyEnabled property in the build.gradle file enables and disables - ProGuard for release builds. The minifyEnabled property is part of the - buildTypes release block that controls the settings applied to - release builds. Set the minifyEnabled property to true to enable - ProGuard, as shown in this example.

+

Features in this document depend on:

+ -
-  android {
-   ...
- 
-    buildTypes {
-        release {
-            minifyEnabled true
-            proguardFiles getDefaultProguardFile('proguard-android.txt'),
-            'proguard-rules.pro'
-        }
-    }
-  }
-  
+

Shrink Your Code

-

The getDefaultProguardFile('proguard-android.txt') method obtains the default - ProGuard settings from the Android SDK tools/proguard/ folder. The - proguard-android-optimize.txt 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 proguard-rules.pro file at the root of the module, - so you can also easily add custom ProGuard rules specific to the current module.

+

To enable code shrinking with ProGuard, add minifyEnabled true +to the appropriate build type in your build.gradle file.

-

You can also add ProGuard files to the getDefaultProguardFile - directive for all release builds or as part of the productFlavor settings in the - build.gradle file to customize the settings applied to build variants. This example - adds the proguard-rules-new.pro to the proguardFiles - directive and the other-rules.pro file to the flavor2 product flavor.

+

Be aware that code shrinking slows down the build time, so you should avoid +using it on your debug build if possible. However, it's important that you +do enable code shrinking on your final APK used for testing, because it might +introduce bugs if you do not sufficiently customize which +code to keep.

+ +

For example, the following snippet from a build.gradle file +enables code shrinking for the release build:

-    android {
-   ...
- 
+android {
+    buildTypes {
+        release {
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile(‘proguard-android.txt'),
+                    'proguard-rules.pro'
+        }
+    }
+    ...
+}
+
+ +

Note: Android Studio disables ProGuard when +using Instant +Run.

+ +

In addition to the minifyEnabled property, the +proguardFiles property defines the ProGuard rules:

+ + + +

To add more ProGuard rules that are specific to each build variant, add +another proguardFiles property in the corresponding +productFlavor block. For example, the following Gradle file adds +flavor2-rules.pro to the flavor2 product flavor. Now +flavor2 uses all three ProGuard rules because those from the +release block are also applied.

+ +
+android {
+    ...
     buildTypes {
         release {
             minifyEnabled true
             proguardFiles getDefaultProguardFile('proguard-android.txt'),
-            'proguard-rules.pro', 'proguard-rules-new.pro'
+                   'proguard-rules.pro'
         }
     }
- 
-   productFlavors {
+    productFlavors {
         flavor1 {
         }
         flavor2 {
-            proguardFile 'other-rules.pro'
+            proguardFile 'flavor2-rules.pro'
         }
     }
- }
-  
- - -

Configuring ProGuard

- -

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:

- - - -

The default ProGuard configuration file tries to cover general cases, but you might - encounter exceptions such as ClassNotFoundException, which happens when ProGuard - strips away an entire class that your application calls.

- -

You can fix errors when ProGuard strips away your code by adding a -keep line in - the ProGuard configuration file. For example:

-
--keep public class <MyClass>
+}
 
-

There are many options and considerations when using the -keep option, so it is - highly recommended that you read the - ProGuard - Manual for more information about customizing your configuration file. The - Overview of Keep options and Examples sections are particularly helpful. - The Troubleshooting - section of the ProGuard Manual outlines other common problems you might encounter - when your code gets stripped away.

+

With each build, ProGuard outputs the following files:

+
+
dump.txt
+
Describes the internal structure of all the class files in the APK.
-

Decoding Obfuscated Stack Traces

+
mapping.txt
+
Provides a translation between the original and obfuscated class, method, and +field names.
-

When your obfuscated code outputs a stack trace, the method names are obfuscated, which makes - debugging hard, if not impossible. Fortunately, whenever ProGuard runs, it outputs a - mapping.txt file, which shows you the original class, method, and field names - mapped to their obfuscated names.

+
seeds.txt
+
Lists the classes and members that were not obfuscated.
-

The retrace.bat script on Windows or the retrace.sh script on Linux - or Mac OS X can convert an obfuscated stack trace to a readable one. It is located - in the <sdk_root>/tools/proguard/ directory. The syntax for executing the - retrace tool is:

-
retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
-

For example:

+
usage.txt
+
Lists the code that was removed from the APK.
+
-
retrace.bat -verbose mapping.txt obfuscated_trace.txt
+

These files are saved at +<module-name>/build/outputs/mapping/release/.

-

If you do not specify a value for <stacktrace_file>, the retrace tool reads - from standard input.

-

Debugging considerations for published applications

+

Customize which code to keep

-

Save the mapping.txt file for every release that you publish to your users. - By retaining a copy of the mapping.txt file for each release build, - you ensure that you can debug a problem if a user encounters a bug and submits an obfuscated stack trace. - A project's mapping.txt file is overwritten every time you do a release build, so you must be - careful about saving the versions that you need. The file is stored in the app build/outs/ folder.

+

For some situations, the default ProGuard configuration file +(proguard-android.txt) is sufficient and ProGuard removes all—and +only—the unused code. However, many situations are difficult for ProGuard to +analyze correctly and it might remove code your app actually needs. Some +examples of when it might incorrectly remove code include:

-

For example, say you publish an application and continue developing new features of - the application for a new version. You then do a release build using ProGuard soon after. The - build overwrites the previous mapping.txt file. A user submits a bug report - containing a stack trace from the application that is currently published. You no longer have a way - of debugging the user's stack trace, because the mapping.txt file associated with the version - on the user's device is gone. There are other situations where your mapping.txt file can be overwritten, so - ensure that you save a copy for every release that you anticipate you have to debug.

+ -

How you save the mapping.txt files is your decision. For example, you can rename - the files to include a version or build number, or you can version control them along with your - source code.

+

Testing your app should reveal any errors caused by inappropriately removed +code, but you can also inspect what code was removed by reviewing the +usage.txt output file saved in +<module-name>/build/outputs/mapping/release/.

+ +

To fix errors and force ProGuard to keep certain code, add a -keep line in the ProGuard configuration file. For example:

+ +
+-keep public class MyClass
+
+ +

Alternatively, you can add the @Keep +annotation to the code you want to keep. Adding @Keep 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 Annotations Support +Library.

+ + +

There are many considerations you should make when using the +-keep option; for more information about customizing your +configuration file, read the +ProGuard Manual. The +Troubleshooting section outlines other common problems you might encounter +when your code gets stripped away.

+ + +

Decode an obfuscated stack trace

+ +

After ProGuard shrinks your code, reading a stack trace is difficult (if not +impossible) because the method names are obfuscated. Fortunately, ProGuard +creates a mapping.txt 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 +<module-name>/build/outputs/mapping/release/ directory.

+ + +

Be aware that the mapping.txt 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 +mapping.txt 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.

+ +

When publishing your app on Google Play, you can upload the +mapping.txt 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 deobfuscate +crash stack traces.

+ +

To convert an obfuscated stack trace to a readable one yourself, use the +retrace script (retrace.bat on Windows; +retrace.sh on Mac/Linux). It is located in the +<sdk-root>/tools/proguard/ directory. The script takes the +mapping.txt file and your stack trace, producing a new, readable +stack trace. The syntax for using the retrace tool is:

+ +
+retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
+
+ +

For example:

+ +
+retrace.bat -verbose mapping.txt obfuscated_trace.txt
+
+ +

If you do not specify the stack trace file, the retrace tool reads from +standard input.

+ +

Shrink Your Resources

+ +

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.

+ +

To enable resource shrinking, set the shrinkResources property +to true in your build.gradle file (alongside +minifyEnabled for code shrinking). For example:

+ +
+android {
+    ...
+    buildTypes {
+        release {
+            shrinkResources true
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'),
+                    'proguard-rules.pro'
+        }
+    }
+}
+
+ +

If you haven't already built your app using minifyEnabled for +code shrinking, then try that before enabling shrinkResources, +because you might need to edit your proguard-rules.pro file to +keep classes or methods that are created or invoked dynamically before you +start removing resources.

+ +

Note: The resource shrinker currently does not +remove resources defined in a values/ 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 issue 70869.

+ + +

Customize which resources to keep

+ +

If there are specific resources you wish to keep or discard, create an XML +file in your project with a <resources> tag 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 +wild card.

+ +

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 +res/raw/keep.xml. The build does not package this file into your +APK.

+ +

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 keep.xml 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.

+ +

Enable strict reference checks

+ +

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 AppCompat +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.

+ +

For example, the following code causes all resources with the +img_ prefix to be marked as used.

+ +
+String name = String.format("img_%1d", angle + 1);
+res = getResources().getIdentifier(name, "drawable", getPackageName());
+
+ +

The resource shrinker also looks through all the string constants in your +code, as well as various res/raw/ resources, looking for resource +URLs in a format similar to +file:///android_res/drawable//ic_plus_anim_016.png. 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.

+ +

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 shrinkMode to strict in the +keep.xml file, as follows:

+ +
+<?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 tools:keep attribute.

+ +

Remove unused alternative resources

+ +

The 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 resConfigs property to +remove alternative resource files that your app does not need.

+ +

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 resConfig property. Any resources for +languages not specified are removed.

+ +

The following snippet shows how to limit your language resources to just +English and French:

+ +
+android {
+    defaultConfig {
+        ...
+        resConfigs "en", "fr"
+    }
+}
+
+ +

To customize which screen density or ABI resources to include in your APK, +instead use APK +splits to build different APKs for different devices.

+ +

Merge duplicate resources

+ +

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 shrinkResources property and +cannot be disabled, because it is necessary to avoid errors when multiple +resources match the name your code is looking up.

+ +

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.

+ +

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 sourceSet property of your +build.gradle file—for example if both src/main/res/ +and src/main/res2/ contain identical resources.

+ +

Troubleshoot resource shrinking

+ +

When you shrink resources, the Gradle Console shows a summary of the +resources that it removed from the app package. For example:

+ +
+:android:shrinkDebugResources
+Removed unused resources: Binary resource data reduced from 2570KB to 1711KB: Removed 33%
+:android:validateDebugSigning
+
+ +

Gradle also creates a diagnostic file named resources.txt in +<module-name>/build/outputs/mapping/release/ (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.

+ +

For example, to find out why @drawable/ic_plus_anim_016 is +still in your APK, open the resources.txt file and search for that +file name. You might find that it's referenced from another resource, as +follows:

+ +
+16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
+16:25:48.009 [QUIET] [system.out]     @drawable/ic_plus_anim_016
+
+ +

You now need to know why @drawable/add_schedule_fab_icon_anim +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 add_schedule_fab_icon_anim (that is, its R.drawable ID was +found in the reachable code).

+ +

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:

+ +
+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.
+
+ +

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 +tools:discard attribute to inform the build system to remove it, +as described in the section about how to customize which resources to keep.

diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs index baa51bcc52c96..c390523b24901 100644 --- a/docs/html/tools/tools_toc.cs +++ b/docs/html/tools/tools_toc.cs @@ -96,6 +96,8 @@ Improving Your Code with lint
  • Improving Code Inspection with Annotations
  • +
  • + Shrink Your Code and Resources
  • Supporting URLs and App Indexing in Android Studio
  • @@ -226,7 +228,6 @@ class="en">Tools Help
  • mksdcard
  • -
  • ProGuard
  • Tracer for OpenGL ES