Generating Efficient APK by Reducing Size & Improving Performance

2c9f04076de133db434c7d9966ac6f6b?s=47 Paresh Mayani
November 05, 2017

Generating Efficient APK by Reducing Size & Improving Performance

Talk delivered in GDG Ahmedabad DevFest 2017 (#DevFestAhm) on 5th November, 2017.

Talked about various tips/tricks and steps to reduce apk size. Also covered some of the tools that I have used for reducing apk size.

Enjoy actual presentation with GIFs http://bit.ly/reduce-apk-size-drive

2c9f04076de133db434c7d9966ac6f6b?s=128

Paresh Mayani

November 05, 2017
Tweet

Transcript

  1. Generating Efficient APK by Reducing Size & Improving Performance

  2. Slides Slides: • Presentation with GIFs: http://bit.ly/reduce-apk-size-drive • Speakerdeck: http://bit.ly/reduce-apk-size

  3. When we announced #DevFestAhm Source: https://media.giphy.com/media/11sBLVxNs7v6WA/giphy.gif

  4. When registration started Source:

  5. Thank You all for coming for my session Source: https://media.giphy.com/media/10Shl99Vghh5aU/giphy.gif

  6. @pareshmayani

  7. Smart Phones Ecosystem

  8. Limited Battery

  9. Limited Battery Limited Storage

  10. Limited Battery Limited Storage Limited RAM

  11. Limited Battery Limited Storage Limited RAM Limited processing power

  12. Limited Battery Limited Storage Limited RAM Limited processing power Limited

    Data/Network Connectivity
  13. Limited Battery Limited Storage Limited RAM Limited processing power Limited

    Data/Network Connectivity Billion Users
  14. Why Apk size is important?

  15. Those big and bloated apk... Source: https://media.giphy.com

  16. And when you can’t use such big apk That moment

    when apk is crashing Waste of user’s time Waste of user’s data pack Source: https://media.giphy.com
  17. Because everyone doesn’t have OnePlus Source: https://media.giphy.com/media/l0MYQgkYlybdCYD3a/giphy.gif

  18. Why apk size is important? 1. Internet connectivity 2. Device

    specifications 3. Billion Users: To get your next billion users
  19. 1. Internet Connectivity Limited internet connectivity (In growing countries like

    India) Limited data pack/plan Costly data plan (Each bytes affects user’s wallet) Large app size causes longer time to download All users don’t have good internet bandwidth/connectivity
  20. The Average Internet Speed In India: Steady Progress Source: https://dazeinfo.com/2017/06/02/india-internet-speed-growth-q1-2017/

  21. Good news: 4G is getting rolled out in India Source:

    https://media.giphy.com
  22. 2. Device specifications Device specification includes: Storage , Battery, RAM,

    Processing Power Low/Mid range devices have 8GB/16GB storage Low/Mid range devices have 1GB/2GB RAM Lesser the storage your app uses, user can enjoy more apps and can store more pictures/videos All users don’t have higher specification devices
  23. Google IO 2017 - Points > 100M users came online

    in 2016 1B 2G devices expected in 2020 50% of India is on 2G 33% users run out of storage in India every day Data is expensive – it costs ~$2 to download a 40MB free app in India Source: Google IO 2017 & https://ashishb.net/tech/google-io-2017-android-notes/
  24. Apk size has an impact on How fast your app

    loads How much memory it uses How much power it consumes
  25. What goes inside apk Let’s Analyse using Apk Analyser

  26. Case Study Let’s take my any project P.S. It’s already

    partially optimised
  27. Assumption We all follow at least some optimisations

  28. None
  29. Raw File size: Actual size of the apk file

  30. Download size: Estimated size of file for the new installations

    (Google play store server highly optimised file)
  31. res: contains all the resources files like images, menus, layouts,

    etc. (those resources which aren’t compiled into resources.arsc)
  32. assets: Contains the app's assets like fonts

  33. classes.dex: dex file which contains all the byte code files

    of your java code that will run on Dalvik/ART virtual machine
  34. lib: Contains the compiled code that is specific to the

    software layer of a processor.
  35. resources.arsc: Contains compiled resources. Contains the XML content from all

    configurations of the res/values/ folder.
  36. META-INF: Contains the CERT.SF and CERT.RSA signature files, as well

    as the MANIFEST.MF manifest file
  37. AndroidManifest.xml: Contains the core Android manifest file

  38. Files to concentrate on res + assets + classes.dex +

    lib + resources.arsc = 98.7%
  39. 1. Reduce ‘res’ count & size

  40. Remove unused resources Analyse -> Inspect code...

  41. [Result] Remove unused resources `res` Reduction => 54.9% to 48.1%

    = Total 6.8% reduction Raw File Size => 24.1 MB to 21.9 MB = -2.2 MB Download Size => 21.8 MB to 19.7 MB = -2.1 MB
  42. Shrinking resources android { buildTypes { release { minifyEnabled true

    shrinkResources true } }
  43. [Result] Shrinking resources `res` Reduction => 48.1% to 46.3% =

    Total 1.8% reduction Raw File Size => 21.9 MB to 21.2 MB = -0.7 MB Download Size => 19.7 MB to 19 MB = -0.7 MB
  44. Exclude Sparse Translation android { defaultConfig { resConfigs "en", "fr"

    } }
  45. [Result] Exclude Sparse Translation Raw File Size => 21.2 MB

    to 20.5 MB = -0.7 MB Download Size => 19 MB to 18.9 MB = -0.1 MB
  46. Reusing resources Scenario: ic_arrow_collapse & ic_arrow_expand Include only one set

    of icons Create RotateDrawable for another <?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_arrow_expand" android:fromDegrees="180" android:pivotX="50%" android:pivotY="50%" android:toDegrees="180" />
  47. Reusing resources - setColorFilter Include only one set of icons

    Apply color filter PorterDuff.Mode mMode = PorterDuff.Mode.SRC_ATOP; Drawable d = getResources().getDrawable(R.drawable.ic_tier_pressure_fluid); d.setColorFilter(ContextCompat.getColor(this, R.color.colorAccent),mMode);
  48. Shape Drawables Using XML, you can create simple set of

    shapes Occupies less memory than actual images <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <stroke android:width="5dp" android:color="#D8FDFB" /> <padding android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp" /> <corners android:radius="4dp" /> <solid android:color="#f0456000" /> </shape>
  49. None
  50. Vector Drawables Based on Vector Graphics Scaled without loss of

    display quality, means same file is resized for different screen densities without loss of image quality VectorDrawable & VectorDrawableCompat AnimatedVectorDrawable & AnimatedVectorDrawableCompat
  51. Vector Asset Studio

  52. Crunch PNG files aapt tool can optimize the image resources

    placed in res/drawable/ with lossless compression can convert a true color PNG that does not require more than 256 colors to an 8-bit PNG with a color palette. With Android plugin for Gradle 3.0.0 , AAPT2 is now enabled by default. android { aaptOptions { cruncherEnabled true } }
  53. Optimise PNG images Command Utility tools PngCrush, pngquant for Lossy

    compression Pngquant has a GUI tool - ImageOptim for Mac
  54. Optimise PNG images - ImageOptim

  55. Optimise video files HD Quality videos are not required for

    mobile apps Compress it using tools available over web
  56. Step 1 - Result Raw File Size => 24.1 MB

    to 17.3 MB = -6.8 MB Download Size => 21.8 MB to 15.7 MB = -6.1 MB
  57. 2. Reduce ‘assets’ size

  58. Use downloadable fonts Remove font files from ‘assets’ folder Use

    downloadable fonts
  59. How does Downloadable font works A font provider is an

    application that retrieves fonts and caches them locally so other apps can request and share fonts.
  60. Step 2 - Result Raw File Size => 17.3 MB

    to 14.6 MB = -2.7 MB Download Size => 15.7 MB to 13 MB = -2.7 MB
  61. Reduce ‘dex’ count & size

  62. Minifying code android { buildTypes { release { minifyEnabled true

    shrinkResources true } } }
  63. Proguard buildTypes { release { minifyEnabled true shrinkResources true proguardFiles

    getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFile "$project.rootDir/settings/proguard_files/proguard-square-okhttp3.pro" proguardFile "$project.rootDir/settings/proguard_files/proguard-google-play-services.pro" proguardFile "$project.rootDir/settings/proguard_files/proguard-okio.pro" proguardFile "$project.rootDir/settings/proguard_files/proguard-crashlytics.pro" proguardFile "$project.rootDir/settings/proguard_files/proguard-gson.pro" } ... ... } }
  64. Analyze and maintain dependencies You never know which sdk/libraries includes

    what dependencies ./gradlew app:dependencies
  65. Analyse dependencies +--- com.android.support:design:26.1.0 | +--- com.android.support:support-v4:26.1.0 | | +---

    com.android.support:support-compat:26.1.0 | | | +--- com.android.support:support-annotations:26.1.0 | | | \--- android.arch.lifecycle:runtime:1.0.0 | | | +--- android.arch.lifecycle:common:1.0.0 | | | | \--- com.android.support:support-annotations:26.1.0 | | | +--- android.arch.core:common:1.0.0 | | | | \--- com.android.support:support-annotations:26.1.0 | | | \--- com.android.support:support-annotations:26.1.0 | | +--- com.android.support:support-media-compat:26.1.0 | | | +--- com.android.support:support-annotations:26.1.0 | | | \--- com.android.support:support-compat:26.1.0 (*) | | +--- com.android.support:support-core-utils:26.1.0 | | | +--- com.android.support:support-annotations:26.1.0 | | | \--- com.android.support:support-compat:26.1.0 (*) | | +--- com.android.support:support-core-ui:26.1.0 | | | +--- com.android.support:support-annotations:26.1.0 | | | \--- com.android.support:support-compat:26.1.0 (*) | | \--- com.android.support:support-fragment:26.1.0 | | +--- com.android.support:support-compat:26.1.0 (*) | | +--- com.android.support:support-core-ui:26.1.0 (*) | | \--- com.android.support:support-core-utils:26.1.0 (*)
  66. Analyze and maintain dependencies Exclude repetitive dependencies Benefits: • Can

    avoid version conflicts • Can avoid multiple copy of same sdk
  67. Analyze and maintain dependencies dependencies { ... ... compile('co.adcel.android:adcel:1.2.1') {

    exclude group: "com.google.android.gms" // exclude group: "com.startapp.android" // exclude group: "com.personagraph" exclude group: "com.flurry" exclude group: "com.android.support" } compile ("jp.wasabeef:recyclerview-animators:2.2.6") { exclude group: "com.android.support" } }
  68. Google play services Include only required sub-sdks from Google play

    service compile 'com.google.android.gms:play-services-gcm:' + rootProject.ext.PLAY_SERVICE_LIB_VERSION compile 'com.google.android.gms:play-services-location:' + rootProject.ext.PLAY_SERVICE_LIB_VERSION compile 'com.google.android.gms:play-services-maps:' + rootProject.ext.PLAY_SERVICE_LIB_VERSION compile 'com.google.android.gms:play-services-places:' + rootProject.ext.PLAY_SERVICE_LIB_VERSION compile 'com.google.android.gms:play-services-ads:' + rootProject.ext.PLAY_SERVICE_LIB_VERSION
  69. Reduce native ‘libs’ code

  70. Remove deprecated httpclient jars Remove legacy jars • Httpclient-4.5.2.jar •

    Httpcore-4.4.4.jar useLibrary 'org.apache.http.legacy'
  71. [Result] Remove deprecated httpclient jars Raw File Size => 14.6

    MB to 14.5 MB = -0.1 MB
  72. Splitting apks Configure multiple apks for different densities Configure multiple

    apks for different CPU architecture (ABI)
  73. Configure multiple apks for densities android { ... splits {

    // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. enable true // Specifies a list of screen densities Gradle should not create multiple APKs for. exclude "ldpi", "xxhdpi", "xxxhdpi" // Specifies a list of compatible screen size settings for the manifest. compatibleScreens 'small', 'normal', 'large', 'xlarge' } } }
  74. Configure multiple apks for ABIs android { ... splits {

    // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. enable true // By default all ABIs are included, so use reset() and include to specify that we only // want APKs for x86, armeabi-v7a, and mips. // Resets the list of ABIs that Gradle should create APKs for to none. reset() // Specifies a list of ABIs that Gradle should create APKs for. include "x86", "armeabi-v7a", "mips" // Specifies that we do not want to also generate a universal APK that includes all ABIs. universalApk false } } }
  75. Total Savings ??

  76. Total Savings Raw File Size => 24.1 MB to 14.5

    MB = -9.4 MB Download Size => 21.8 MB to 13 MB = -8.8 MB Notes: • Splitting is not applied yet • This was already partially optimised, as all devs used to follow at least some optimisations
  77. Remember Lesser is always better Less number of files =

    low maintenance time Less number of files = reduced apk size = faster loading time Lesser the apk size = faster the download time Less number of files = faster building time
  78. +PareshMayani @pareshmayani Technical Lead - Android @ Simform Manager, GDG

    Ahmedabad
  79. No Questions!!

  80. Thank You! Paresh Mayani @pareshmayani Slides: • Presentation with GIFs:

    http://bit.ly/reduce-apk-size-drive • Speakerdeck: http://bit.ly/reduce-apk-size