Share
Embed
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
Paresh Mayani
November 05, 2017
Transcript
80 slides
-
Limited Battery Limited Storage Limited RAM Limited processing power Limited
Data/Network Connectivity -
Limited Battery Limited Storage Limited RAM Limited processing power Limited
Data/Network Connectivity Billion Users -
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 -
Why apk size is important? 1. Internet connectivity 2. Device
specifications 3. Billion Users: To get your next billion users -
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 -
Good news: 4G is getting rolled out in India Source:
https://media.giphy.com -
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 -
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/ -
Apk size has an impact on How fast your app
loads How much memory it uses How much power it consumes -
Case Study Let’s take my any project P.S. It’s already
partially optimised -
Download size: Estimated size of file for the new installations
(Google play store server highly optimised file) -
res: contains all the resources files like images, menus, layouts,
etc. (those resources which aren’t compiled into resources.arsc) -
classes.dex: dex file which contains all the byte code files
of your java code that will run on Dalvik/ART virtual machine -
lib: Contains the compiled code that is specific to the
software layer of a processor. -
resources.arsc: Contains compiled resources. Contains the XML content from all
configurations of the res/values/ folder. -
META-INF: Contains the CERT.SF and CERT.RSA signature files, as well
as the MANIFEST.MF manifest file -
Files to concentrate on res + assets + classes.dex +
lib + resources.arsc = 98.7% -
[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 -
Shrinking resources android { buildTypes { release { minifyEnabled true
shrinkResources true } } -
[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 -
[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 -
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" /> -
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); -
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> -
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 -
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 } } -
Optimise PNG images Command Utility tools PngCrush, pngquant for Lossy
compression Pngquant has a GUI tool - ImageOptim for Mac -
Optimise video files HD Quality videos are not required for
mobile apps Compress it using tools available over web -
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 -
Use downloadable fonts Remove font files from ‘assets’ folder Use
downloadable fonts -
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. -
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 -
Minifying code android { buildTypes { release { minifyEnabled true
shrinkResources true } } } -
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" } ... ... } } -
Analyze and maintain dependencies You never know which sdk/libraries includes
what dependencies ./gradlew app:dependencies -
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 (*) -
Analyze and maintain dependencies Exclude repetitive dependencies Benefits: • Can
avoid version conflicts • Can avoid multiple copy of same sdk -
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" } } -
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 -
Remove deprecated httpclient jars Remove legacy jars • Httpclient-4.5.2.jar •
Httpcore-4.4.4.jar useLibrary 'org.apache.http.legacy' -
[Result] Remove deprecated httpclient jars Raw File Size => 14.6
MB to 14.5 MB = -0.1 MB -
Splitting apks Configure multiple apks for different densities Configure multiple
apks for different CPU architecture (ABI) -
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' } } } -
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 } } } -
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 -
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 -
Thank You! Paresh Mayani @pareshmayani Slides: • Presentation with GIFs:
http://bit.ly/reduce-apk-size-drive • Speakerdeck: http://bit.ly/reduce-apk-size