Home | History | Annotate | Download | only in performance
      1 page.title=Reduce APK Size
      2 trainingnavtop=true
      3 
      4 @jd:body
      5 
      6 <div id="tb-wrapper">
      7 <div id="tb">
      8 
      9 <h2>This lesson teaches you to</h2>
     10 <ol>
     11   <li><a href="#apk-structure">Understand the APK Structure</a></li>
     12   <li><a href="#reduce-resources">Reduce Resource Count and Size</a></li>
     13   <li><a href="#reduce-code">Reduce Native and Java Code</a></li>
     14   <li><a href="#multiple-apks">Maintain Multiple Lean APKs</a></li>
     15 </ol>
     16 
     17 <h2>
     18   You should also read
     19 </h2>
     20 
     21 <ul>
     22   <li>
     23     <a href="{@docRoot}studio/build/shrink-code.html">Shrink Your Code and
     24     Resources</a>
     25   </li>
     26 </ul>
     27 
     28 
     29 </div>
     30 </div>
     31 
     32 <p>
     33   Users often avoid downloading apps that seem too large, particularly in
     34   emerging markets where devices connect to often-spotty 2G and
     35   3G networks or work on pay-by-the-byte plans. This article describes how to
     36   reduce your app's APK size, which enables more users to download your app.
     37 </p>
     38 
     39 <h2 id="apk-structure">
     40   Understand the APK Structure
     41 </h2>
     42 
     43 <p>
     44   Before discussing how to reduce the size of your app, it's helpful to
     45   understand the structure of an app's APK. An APK file consists of a ZIP
     46   archive that contains all the files that comprise your app. These files
     47   include Java class files, resource files, and a file containing compiled
     48   resources.
     49 </p>
     50 
     51 <p>
     52 An APK contains the following directories:
     53 </p>
     54 
     55 <ul>
     56   <li>{@code META-INF/}: Contains the <code>CERT.SF</code> and
     57   <code>CERT.RSA</code> signature files, as well as the {@code MANIFEST.MF}
     58   manifest file.
     59   </li>
     60 
     61   <li>{@code assets/}: Contains the app's assets, which the app can retrieve
     62   using an {@link android.content.res.AssetManager} object.
     63   </li>
     64 
     65   <li>
     66   {@code res/}: Contains resources that aren't compiled into
     67   <code>resources.arsc</code>.
     68   </li>
     69 
     70   <li>{@code lib/}: Contains the compiled code that is specific to the software
     71   layer of a processor. This directory contains a subdirectory for each
     72   platform type, like <code>armeabi</code>, <code>armeabi-v7a</code>,
     73   <code>arm64-v8a</code>, <code>x86</code>, <code>x86_64</code>, and
     74   <code>mips</code>.
     75   </li>
     76 </ul>
     77 
     78 <p>
     79 An APK also contains the following files. Among them,
     80 only <code>AndroidManifest.xml</code> is mandatory.
     81 </p>
     82 
     83 <ul>
     84   <li>{@code resources.arsc}: Contains compiled resources. This file contains
     85   the XML content from all configurations of the <code>res/values/</code>
     86   folder. The packaging tool extracts this XML content, compiles it to binary
     87   form, and archives the content. This content includes language strings and
     88   styles, as well as paths to content that is not included directly in the
     89   <code>resources.arsc</code> file, such as layout files and images.
     90   </li>
     91 
     92   <li>{@code classes.dex}: Contains the classes compiled in the DEX file format
     93   understood by the Dalvik/ART virtual machine.
     94   </li>
     95 
     96   <li>{@code AndroidManifest.xml}: Contains the core Android manifest file.
     97   This file lists the name, version, access rights, and referenced library
     98   files of the app. The file uses Android's binary XML format.
     99   </li>
    100 </ul>
    101 
    102 <h2 id="reduce-resources">
    103   Reduce Resource Count and Size
    104 </h2>
    105 
    106 <p>
    107   The size of your APK has an impact on how fast your app loads, how much
    108   memory it uses, and how much power it consumes. One of the simple ways to
    109   make your APK smaller is to reduce the number and size of the
    110   resources it contains. In particular, you can remove resources
    111   that your app no longer uses, and you can use scalable {@link
    112   android.graphics.drawable.Drawable} objects in place of image files. This
    113   section discusses these methods as well as several other ways that you can
    114   reduce the resources in your app to decrease the overall size of your APK.
    115 </p>
    116 
    117 <h3 id="remove-unused">
    118   Remove Unused Resources
    119 </h3>
    120 
    121 <p>
    122   The <a href="{@docRoot}studio/write/lint.html">{@code lint}</a> tool, a
    123   static code analyzer included in Android Studio, detects resources in your
    124   <code>res/</code> folder that your code doesn't reference. When the
    125   <code>lint</code> tool discovers a potentially unused resource in your
    126   project, it prints a message like the following example.
    127 </p>
    128 
    129 <pre class="no-pretty-print">
    130 res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
    131     to be unused [UnusedResources]
    132 </pre>
    133 <p class="note">
    134   <strong>Note:</strong> The <code>lint</code> tool doesn't scan the {@code
    135   assets/} folder, assets that are referenced via reflection, or library files
    136   that you've linked to your app. Also, it doesn't remove resources; it only
    137   alerts you to their presence.
    138 </p>
    139 
    140 <p>
    141   Libraries that you add to your code may include unused resources. Gradle can
    142   automatically remove resources on your behalf if you enable <a href=
    143   "{@docRoot}studio/build/shrink-code.html">{@code shrinkResources}</a> in
    144   your app's <code>build.gradle</code> file.
    145 </p>
    146 
    147 <pre class="prettyprint">
    148 android {
    149     // Other settings
    150 
    151     buildTypes {
    152         release {
    153             minifyEnabled true
    154             shrinkResources true
    155             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    156         }
    157     }
    158 }
    159 </pre>
    160 <p>
    161   To use {@code shrinkResources}, you must enable code shrinking. During the
    162   build process, first <a href=
    163   "{@docRoot}studio/build/shrink-code.html">ProGuard</a> removes unused code
    164   but leaves unused resources. Then Gradle removes the unused resources.
    165 </p>
    166 
    167 <p>
    168   For more information about ProGuard and other ways
    169   Android Studio helps you reduce APK size, see <a href=
    170   "{@docRoot}studio/build/shrink-code.html">Shrink Your Code and Resources</a>.
    171 </p>
    172 
    173 <p>
    174   In Android Gradle Plugin 0.7 and higher, you can declare the configurations
    175   that your app supports. Gradle passes this information to the build system
    176   using the {@code resConfig} and {@code resConfigs} flavors and the
    177   <code>defaultConfig</code> option. The build system then prevents resources
    178   from other, unsupported configurations from appearing in the APK, reducing
    179   the APK's size. For more information about this feature, see <a href=
    180   "{@docRoot}studio/build/shrink-code.html#unused-alt-resources">Remove unused
    181   alternative resources</a>.
    182 </p>
    183 
    184 <h3 id="minimize">
    185   Minimize Resource Use from Libraries
    186 </h3>
    187 
    188 <p>
    189   When developing an Android app, you usually use external libraries to improve
    190   your app's usability and versatility. For example, you might reference the
    191   <a href="{@docRoot}topic/libraries/support-library/index.html">Android
    192   Support Library</a> to improve the user experience on older devices, or you
    193   could use <a class="external-link" href=
    194   "https://developers.google.com/android/guides/overview">Google Play
    195   Services</a> to retrieve automatic translations for text within your app.
    196 </p>
    197 
    198 <p>
    199   If a library was designed for a server or desktop, it can include many
    200   objects and methods that your app doesnt need. To include only the parts of
    201   the library that your app needs, you can edit the library's files if the
    202   license allows you to modify the library. You can also use an alternative,
    203   mobile-friendly library to add specific functionality to your app.
    204 </p>
    205 
    206 <p class="note">
    207   <strong>Note:</strong> <a href=
    208   "{@docRoot}studio/build/shrink-code.html">ProGuard</a> can clean up some
    209   unnecessary code imported with a library, but it can't remove a library's
    210   large internal dependencies.
    211 </p>
    212 
    213 <h3 id="support-densities">
    214   Support Only Specific Densities
    215 </h3>
    216 
    217 <p>
    218   Android supports a very large set of devices, encompassing a variety of
    219   screen densities. In Android 4.4 (API level 19) and higher, the framework
    220   supports various densities: <code>ldpi</code>, <code>mdpi</code>,
    221   <code>tvdpi</code>, <code>hdpi,</code> <code>xhdpi</code>,
    222   <code>xxhdpi</code> and <code>xxxhdpi</code>. Although Android supports all
    223   these densities, you don't need to export your rasterized assets to each
    224   density.
    225 </p>
    226 
    227 <p>
    228   If you know that only a small percentage of your users have devices with
    229   specific densities, consider whether you need to bundle those densities into
    230   your app. If you don't include resources for a specific screen density,
    231   Android automatically scales existing resources originally designed for other
    232   screen densities.
    233 </p>
    234 
    235 <p>
    236   If your app needs only scaled images, you can save even more space by having
    237   a single variant of an image in <code>drawable-nodpi/</code>. We recommend
    238   that every app include at least an <code>xxhdpi</code> image variant.
    239 </p>
    240 
    241 <p>
    242   For more information screen densities, see <a class="external-link" href=
    243   "{@docRoot}about/dashboards/index.html#Screens">Screen Sizes and
    244   Densities</a>.
    245 </p>
    246 
    247 <h3 id="reduce-frames">
    248   Reduce Animation Frames
    249 </h3>
    250 
    251 <p>
    252   Frame-by-frame animations can drastically increase the size of your APK.
    253   Figure 1 shows an example of a frame-by-frame animation separated into
    254   multiple PNG files within a directory. Each image is one frame in the
    255   animation.
    256 </p>
    257 
    258 <p>
    259   For each frame that you add to the animation, you increase the number of
    260   images stored in the APK. In Figure 1, the image animates at 30 FPS within
    261   the app. If the image animated at only 15 FPS instead, the animation would
    262   require only half the number of needed frames.
    263 </p>
    264 
    265 <figure id="fig-frame-animations">
    266   <img src="{@docRoot}images/training/performance/animation-frames.png" srcset=
    267   "{@docRoot}images/training/performance/animation-frames.png 1x, {@docRoot}images/training/performance/animation-frames_2x.png 2x"
    268   width="803" alt="">
    269   <figcaption>
    270     <strong>Figure 1.</strong> Frame by frame animations stored as resources.
    271   </figcaption>
    272 </figure>
    273 
    274 <h3 id="use-drawables">
    275   Use Drawable Objects
    276 </h3>
    277 
    278 <p>
    279   Some images don't require a static image resource; the framework can
    280   dynamically draw the image at runtime instead. {@link
    281   android.graphics.drawable.Drawable} objects (<code>&lt;shape&gt;</code> in
    282   XML) can take up a tiny amount of space in your APK. In addition, XML {@link
    283   android.graphics.drawable.Drawable} objects produce monochromatic images
    284   compliant with material design guidelines.
    285 </p>
    286 
    287 <h3 id="reuse-resources">
    288   Reuse Resources
    289 </h3>
    290 
    291 <p>
    292   You can include a separate resource for variations of an image, such as
    293   tinted, shaded, or rotated versions of the same image. We recommend, however,
    294   that you reuse the same set of resources, customizing them as needed at
    295   runtime.
    296 </p>
    297 
    298 <p>
    299   Android provides several utilities to change the color of an asset, either
    300   using the {@code android:tint} and {@code tintMode} attributes on Android 5.0
    301   (API level 21) and higher. For lower versions of the platform, use the {@link
    302   android.graphics.ColorFilter} class.
    303 </p>
    304 <p>
    305   You can also omit resources that are only a rotated equivalent of another
    306   resource. The following code snippet provides an example of turning an
    307   "expand" arrow into a "collapse" arrow icon by simply rotating the original
    308   image 180 degrees:
    309 </p>
    310 
    311 <pre class="prettyprint">
    312 &lt;?xml version="1.0" encoding="utf-8"?&gt;
    313 &lt;rotate xmlns:android="http://schemas.android.com/apk/res/android"
    314     android:drawable="@drawable/ic_arrow_expand"
    315     android:fromDegrees="180"
    316     android:pivotX="50%"
    317     android:pivotY="50%"
    318     android:toDegrees="180" /&gt;
    319 </pre>
    320 <h3 id="render-code">
    321   Render From Code
    322 </h3>
    323 
    324 <p>
    325   You can also reduce your APK size by procedurally rendering your images.
    326   Procedural rendering frees up space because you no longer store an image file
    327   in your APK.
    328 </p>
    329 
    330 <h3 id="crunch">
    331   Crunch PNG Files
    332 </h3>
    333 
    334 <p>
    335   The <code>aapt</code> tool can optimize the image resources placed in
    336   <code>res/drawable/</code> with lossless compression during the build
    337   process. For example, the <code>aapt</code> tool can convert a true-color PNG
    338   that does not require more than 256 colors to an 8-bit PNG with a color
    339   palette. Doing so results in an image of equal quality but a smaller memory
    340   footprint.
    341 </p>
    342 
    343 <p>
    344   Keep in mind that the <code>aapt</code> has the following limitations:
    345 </p>
    346 
    347 <ul>
    348   <li>The <code>aapt</code> tool does not shrink PNG files contained in the
    349   <code>asset/</code> folder.
    350   </li>
    351 
    352   <li>Image files need to use 256 or fewer colors for the <code>aapt</code>
    353   tool to optimize them.
    354   </li>
    355 
    356   <li>The <code>aapt</code> tool may inflate PNG files that have already been
    357   compressed. To prevent this, you can use the <code>cruncherEnabled</code>
    358   flag in Gradle to disable this process for PNG files:
    359   </li>
    360 </ul>
    361 
    362 <pre class="prettyprint">
    363 aaptOptions {
    364     cruncherEnabled = false
    365 }
    366 </pre>
    367 <h3 id="compress">
    368   Compress PNG and JPEG Files
    369 </h3>
    370 
    371 <p>
    372   You can reduce PNG file sizes without losing image quality using tools like
    373   <a class="external-link" href=
    374   "http://pmt.sourceforge.net/pngcrush/">pngcrush</a>, <a class="external-link"
    375   href="https://pngquant.org/">pngquant</a>, or <a class="external-link" href=
    376   "https://github.com/google/zopfli">zopflipng</a>. All of these tools can
    377   reduce PNG file size while preserving image quality.
    378 </p>
    379 
    380 <p>
    381   The {@code pngcrush} tool is particularly effective: This tool iterates over
    382   PNG filters and zlib (Deflate) parameters, using each combination of filters
    383   and parameters to compress the image. It then chooses the configuration that
    384   yields the smallest compressed output.
    385 </p>
    386 
    387 <p>
    388   For JPEG files, you can use tools like <a class="external-link" href=
    389   "http://www.elektronik.htw-aalen.de/packjpg/">packJPG</a> that compress JPEG
    390   files into a more compact form.
    391 </p>
    392 
    393 <h3 id="use-webp">
    394   Use WebP File Format
    395 </h3>
    396 
    397 <p>
    398   Instead of using PNG or JPEG files, you can also use the <a class=
    399   "external-link" href="https://developers.google.com/speed/webp/">WebP</a>
    400   file format for your images. The WebP format provides lossy compression (like
    401   JPEG) as well as transparency (like PNG) but can provide better compression
    402   than either JPEG or PNG.
    403 </p>
    404 
    405 <p>
    406   Using the WebP file format has a few notable drawbacks, however. First,
    407   support for WebP is not available in versions of the platform lower than
    408   Android 3.2 (API level 13). Second, it takes a longer amount of time for the
    409   system to decode WebP than PNG files.
    410 </p>
    411 
    412 <p class="note">
    413   <strong>Note:</strong> Google Play accepts APKs only if the included icons
    414   use the PNG format. You can't use other file formats like JPEG or WebP for
    415   app icons if you intend to publish your app through Google Play.
    416 </p>
    417 
    418 <h3 id="vector">
    419   Use Vector Graphics
    420 </h3>
    421 
    422 <p>
    423   You can use vector graphics to create resolution-independent icons and other
    424   scalable media. Using these graphics can greatly reduce your APK footprint.
    425   Vector images are represented in Android as {@link
    426   android.graphics.drawable.VectorDrawable} objects. With a {@link
    427   android.graphics.drawable.VectorDrawable } object, a 100-byte file can
    428   generate a sharp image the size of the screen.
    429 </p>
    430 
    431 <p>
    432   However, it takes a significant amount of time for the system to render each
    433   {@link android.graphics.drawable.VectorDrawable} object, and larger images
    434   take even longer to appear on the screen. Therefore, consider using these
    435   vector graphics only when displaying small images.
    436 </p>
    437 
    438 <p>
    439   For more information on working with {@link
    440   android.graphics.drawable.VectorDrawable } objects, see <a class=
    441   "external-link" href="{@docRoot}training/material/drawables.html">Working
    442   with Drawables</a>.
    443 </p>
    444 
    445 <h2 id="reduce-code">
    446   Reduce Native and Java Code
    447 </h2>
    448 
    449 <p>
    450   There are several methods you can use to reduce the size of the Java and
    451   native codebase in your app.
    452 </p>
    453 
    454 <h3 id="remove-generated">
    455   Remove Unnecessary Generated Code
    456 </h3>
    457 
    458 <p>
    459   Make sure to understand the footprint of any code which is automatically
    460   generated. For example, many protocol buffer tools generate an excessive
    461   number of methods and classes, which can double or triple the size of your
    462   app.
    463 </p>
    464 
    465 <h3 id="remove-enums">
    466   Remove Enumerations
    467 </h3>
    468 
    469 <p>
    470   A single enum can add about 1.0 to 1.4 KB of size to your app's
    471   <code>classes.dex</code> file. These additions can quickly accumulate for
    472   complex systems or shared libraries. If possible, consider using the
    473   <code>@IntDef</code> annotation and <a href=
    474   "{@docRoot}studio/build/shrink-code.html">ProGuard</a> to strip enumerations
    475   out and convert them to integers. This type conversion preserves all of the
    476   type safety benefits of enums.
    477 </p>
    478 
    479 <h3 id="reduce-binaries">
    480   Reduce the Size of Native Binaries
    481 </h3>
    482 
    483 <p>
    484   If your app uses native code and the Android NDK, you can also reduce the
    485   size of your app by optimizing your code. Two useful techniques are
    486   removing debug symbols and not extracting native libraries.
    487 </p>
    488 
    489 <h4 id="remove-debug">
    490   Remove Debug Symbols
    491 </h4>
    492 
    493 <p>
    494   Using debug symbols makes sense if your application is in development and
    495   still requires debugging. Use the <code>arm-eabi-strip</code> tool, provided
    496   in the Android NDK, to remove unnecessary debug symbols from native
    497   libraries. After that, you can compile your release build.
    498 </p>
    499 
    500 <h4 id="extract-false">
    501   Avoid Extracting Native Libraries
    502 </h4>
    503 
    504 <p>
    505   Store {@code .so} files uncompressed in the APK, and set the {@code
    506   android:extractNativeLibs} flag to false in the <a href=
    507   "{@docRoot}guide/topics/manifest/application-element.html">{@code
    508   <application>}</a> element of your app manifest. This will prevent
    509   {@link android.content.pm.PackageManager} from copying out {@code .so} files
    510   from the APK to the filesystem during installation and will have the added
    511   benefit of making delta updates of your app smaller.
    512 </p>
    513 
    514 <h2 id="multiple-apks">
    515   Maintain Multiple Lean APKs
    516 </h2>
    517 
    518 <p>
    519   Your APK can contain content that users download but never use, like regional
    520   or language information. To create a minimal download for your users, you can
    521   segment your app into several APKs, differentiated by factors such as screen
    522   size or GPU texture support.
    523 </p>
    524 
    525 <p>
    526   When a user downloads your app, their device receives the correct APK based
    527   on the device's features and settings. This way, devices don't receive assets
    528   for features that the devices don't have. For example, if a user has a
    529   <code>hdpi</code> device, they dont need <code>xxxhdpi</code> resources that
    530   you might include for devices with higher density displays.
    531 </p>
    532 
    533 <p>
    534   For more information, see <a href=
    535   "{@docRoot}studio/build/configure-apk-splits.html">Configure APK Splits</a>
    536   and <a class="external-link" href=
    537   "{@docRoot}training/multiple-apks/index.html">Maintaining Multiple APKs</a>.
    538 </p>
    539