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><shape></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<?xml version="1.0" encoding="utf-8"?> 313<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" /> 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