• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Reduce APK Size
2trainingnavtop=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>
52An 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>
79An APK also contains the following files. Among them,
80only <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">
130res/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">
148android {
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 doesn’t 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">
363aaptOptions {
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 don’t 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