APP SIZE
Mateusz
Grzechociński
Jacek
Karaśkiewicz
SAVE USERS’ DATA !
Tips for reducing the APK size.
Mateusz
Grzechociński
Jacek
Karaśkiewicz
2Years
1mlnUsers in Dec 2016
14minSDK
200Layouts
62MBAPK size in mid 2016
ANALYZE CURRENT STATE
APK ANALYZER
MID 2016
APK ANALYZER
MID 2016
RAW VS DOWNLOAD
• Focus on both
RAW VS DOWNLOAD
• Focus on both
• Install size
RAW VS DOWNLOAD
• Focus on both
• Install size
• Update size
RAW VS DOWNLOAD
• Focus on both
• Install size
• Update size
APK PATCH SIZE ESTIMATORhttps://github.com/googlesamples/apk-patch-size-estimator
APK PATCH SIZE ESTIMATORhttps://github.com/googlesamples/apk-patch-size-estimator
$ python apk_patch_size_estimator.py --old-file ~/Downloads/IKO3_android_rc_v3.106.114_b8907.apk
--new-file ~/Downloads/IKO3_android_rc_v3.106.122_b9513.apk
New APK size on disk: 29999643 bytes [28.6MB]
Estimated download size for new installs:
Full new APK (gzipped) size: 26227473 bytes [25MB]
Estimated download size for updates from the old APK, using Bsdiff:
Bsdiff patch (gzipped) size: 6858901 bytes [6.54MB]
Estimated download size for updates from the old APK,
using File-by-File:
File-by-File patch (gzipped) size: 3167479 bytes [3.02MB]
APK ANALYZER
MID 2016
AAPT
android {
…
aaptOptions {
cruncherEnabled = true
}
}
AAPT
• No colors?
AAPT
• No colors?
• No alpha?
AAPT
• No colors?
• No alpha?
Standard PS Export
720x510 RGBA
AAPT
AAPT
AAPT
48%
reduction
„for free”
AAPT
• No colors?
• No alpha?
• 256 colors?
AAPT
• No colors?
• No alpha?
• 256 colors?
Standard PS Export
1440x1268 RGBA
2192 colors
AAPT
AAPT
AAPT
0%
reduction
„for free”
AAPT
53MBres/ in GIT
vs
AAPT EFFICIENCY
MID 2016
53MBres/ in GIT
vs
AAPT EFFICIENCY
MID 2016
res/ in APK
53MBres/ in GIT
vs
50,3MB
AAPT EFFICIENCY
MID 2016
res/ in APK
53MBres/ in GIT
vs
50,3MB
5%
reduction
„for free”
AAPT EFFICIENCY
MID 2016
res/ in APK
WHAT IF 256?
1440x1268 RGBA PNG
2192 colors
1440x1268 RGBA PNG
251 colors
vs
WHAT IF 256?
1440x1268 RGBA PNG
2192 colors
1440x1268 RGBA PNG
251 colors
vs
123KB
WHAT IF 256?
1440x1268 RGBA PNG
2192 colors
1440x1268 RGBA PNG
251 colors
vs
123KB 57KB
Do
It
Yourself
GRAPHICS
ANDROID IMAGE FORMATS
• *.png
ANDROID IMAGE FORMATS
• *.png
• *.jpg
ANDROID IMAGE FORMATS
• *.png
• *.jpg
• *.webp
ANDROID IMAGE FORMATS
• *.png
• *.jpg
• *.webp
• *.bmp
ANDROID IMAGE FORMATS
• *.png
• *.jpg
• *.webp
• *.bmp
ANDROID IMAGE FORMATS
• *.gif
• *.png
• *.jpg
• *.webp
ANDROID IMAGE FORMATS
Portable
Network
Graphics
PNGQUANT
Lossy PNG compressor
PNGQUANT
Lossy PNG compressor
+
ZOPFLI
Very good, but slow, deflate or zlib compression.
INPUT
1200x869 RGBA
64249 colors
566KB
ZOPFLI
INPUT
1200x869 RGBA
64249 colors
566KB
1200x869 RGBA
64249 colors
459KB (-19%)
1200x869 RGBA
64249 colors
459KB (-19%)
PNGQUANT
1200x869 Palette
256 colors
126KB (-78%)
INPUT
1200x869 RGBA
64249 colors
566KB
ZOPFLI
ZOPFLI + PNGQUANT
1200x869 Palette
256 colors
117KB (-80%)
1200x869 RGBA
64249 colors
459KB (-19%)
INPUT
1200x869 RGBA
64249 colors
566KB
PNGQUANT
1200x869 Palette
256 colors
126KB (-78%)
ZOPFLI
ZOPFLI +
PNGQUANT
INPUT
PNGQUANT
ZOPFLI
ZOPFLI +
PNGQUANT
PNGQUANT
ZOPFLIINPUT
will be
Joint
Photographic
Experts
Group
CONVERT
Convert between image formats as well as resize an image, blur, crop, despeckle, dither, draw on,
flip, join, re-sample, and much more
GUETZLI
Perceptual JPEG encoder
GUETZLI
Perceptual JPEG encoder
+
BUTTERAUGLI
Estimates the psychovisual difference between two images
1200x869 RGBA PNG
64249 colors
566KB
guetzli binary search
w/ BA 2.0
1200x869 RGBA PNG
64249 colors
566KB
guetzli binary search
w/ BA 2.0
1200x869 RGB JPEG
quality 90
105KB
1200x869 RGBA PNG
64249 colors
566KB
vs
1200x869 Palette
256 colors
117KB
1200x869 RGB JPEG
quality 90
105KB
WEBP
WEBP
API 14+
• Lossy & non-transparent
• better than JPEG
WEBP
API 18+
• Lossless & transparent
• better than PNG
API 14+
• Lossy & non-transparent
• better than JPEG
WEBP
API 18+
• Lossless & transparent
• better than PNG
API 14+
• Lossy & non-transparent
• better than JPEG
1200x869 RGBA PNG
64249 colors
566KB
1200x869 RGBA PNG
64249 colors
566KB
WebP Lossy
1200x869 RGB WebP
quality 80%
61KB
1200x869 RGBA PNG
64249 colors
566KB
WebP Lossy
vs
1200x869 RGB JPEG by Guetzli
quality 90
105KB
1200x869 RGB WebP
quality 80%
61KB
APK RAW SIZE #1
62MB vs
MID 2016
APK RAW SIZE #1
62MB vs
MID 2016 + Graphics optimizations
APK RAW SIZE #1
62MB vs
31MBMID 2016 + Graphics optimizations
50%
reduction
APK RAW SIZE #1
62MB vs
31MBMID 2016 + Graphics optimizations
DENSITIES
XXXHDPI
XXHDPI
XHDPI
HDPI
MDPI
DENSITIES
XXXHDPI
XXHDPI
XHDPI
HDPI
DENSITIES
XXXHDPI
XXHDPI
XHDPI
HDPI
AUTOSCALING
hdpi
AUTOSCALING
hdpi
AUTOSCALING
hdpi
xxxhdpi
downsized to hdpi
vs
AUTOSCALING
hdpi
AUTOSCALING
hdpi
AUTOSCALING
vs
hdpi xxxhdpi
downsized to hdpi
31MB vs
APK RAW SIZE #2
Graphics optimizations
31MB vs
APK RAW SIZE #2
+ Removed all mdpi
+ Removed all but xxxhdpi for large gfx
Graphics optimizations
31MB vs
22MB
APK RAW SIZE #2
+ Removed all mdpi
+ Removed all but xxxhdpi for large gfx
Graphics optimizations
31MB vs
22MB
29%
reduction
APK RAW SIZE #2
+ Removed all mdpi
+ Removed all but xxxhdpi for large gfx
Graphics optimizations
ICONS
VECTORDRAWABLE
VECTORDRAWABLE
• Native support 21+
VECTORDRAWABLE
• Native support 21+
• „gradle" way
VECTORDRAWABLE
• Native support 21+
• „gradle" way
• „support” way
VECTORDRAWABLECOMPAT
android {
…
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
MIGRATING
<vector android:height="50dp"
android:viewportHeight="48.0"
android:viewportWidth="48.0"
android:width="50dp"
xmlns:android=„[…]”>
<path
android:fillAlpha="1"
android:fillColor="@color/iko_blue"
android:pathData=„M40.09,[…]”
android:strokeColor="#00000000"/>
</vector>
iko_ic_topup.png iko_ic_topup.xml
MIGRATING
<vector android:height="50dp"
android:viewportHeight="48.0"
android:viewportWidth="48.0"
android:width="50dp"
xmlns:android=„[…]”>
<path
android:fillAlpha="1"
android:fillColor="@color/iko_blue"
android:pathData=„M40.09,[…]”
android:strokeColor="#00000000"/>
</vector>
SVG
AS
Import
MIGRATING
<vector android:height="50dp"
android:viewportHeight="48.0"
android:viewportWidth="48.0"
android:width="50dp"
xmlns:android=„[…]”>
<path
android:fillAlpha="1"
android:fillColor="@color/iko_blue"
android:pathData=„M40.09,[…]”
android:strokeColor="#00000000"/>
</vector>
SVG
inloop
svg2android
MIGRATING
SVG
POTRACE
Transforming bitmaps into vector graphics
BMP
$ potrace -s iko_ic_topup.bmp
BMP SVG
vs
vs
Animated
Vector
Drawable
Animated
Vector
Drawable
ISSUES
<layer-list /> drawable on Lollipop
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/iko_white"/>
<padding android:top="7dp"
android:bottom="7dp"
android:left="7dp"
android:right="7dp"/>
</shape>
</item>
<item android:drawable=„@drawable/ic_logo_visa"/>
</layer-list>
ISSUES
<layer-list /> drawable on Lollipop
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/iko_white"/>
<padding android:top="7dp"
android:bottom="7dp"
android:left="7dp"
android:right="7dp"/>
</shape>
</item>
<item android:drawable=„@drawable/ic_logo_visa"/>
</layer-list>
REUSING GRAPHICS
REUSING GRAPHICS
Tint
REUSING GRAPHICS
Tint
REUSING GRAPHICS
Tint
REUSING GRAPHICS
Tint
REUSING GRAPHICS
Tint
REUSING GRAPHICS
Tint Rotate
REUSING GRAPHICS
Tint Rotate
22MB vs
APK RAW SIZE #3
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx
22MB vs
APK RAW SIZE #3
+ Switched toVD
+ Reusing icons
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx
22MB vs
20MB
APK RAW SIZE #3
+ Switched toVD
+ Reusing icons
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx
22MB vs
20MB
9%
reduction
APK RAW SIZE #3
+ Switched toVD
+ Reusing icons
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx
~900 PNG icons
~310 PNG icons ~160VD files
WHAT’S UNUSED?
PROGUARD EVERYTHING?
LINT
RESOURCE SHRINKING
RESOURCE SHRINKING
android {
…
buildTypes {
release {
minifyEnabled true
shrinkResources true
}
}
}
RESOURCE SHRINKING
RESOURCE SHRINKING
RESOURCE SHRINKING
RESOURCE SHRINKING
RESOURCE SHRINKING
„if your code makes a call to Resources.getIdentifier(), code is
looking up resource names based on dynamically-generated
strings.
[…] resource shrinker behaves defensively by default and marks all
resources with a matching name format as potentially used and
unavailable for removal.”
https://developer.android.com/studio/build/shrink-code.html
RESOURCE SHRINKING
20MB vs
APK RAW SIZE #4
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
20MB vs
APK RAW SIZE #4
+ Shrinked resourcesGraphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
20MB vs
19MB
APK RAW SIZE #4
+ Shrinked resourcesGraphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
20MB vs
19MB
5%
reduction
APK RAW SIZE #4
+ Shrinked resourcesGraphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
RESOURCES.ARSC
RESOURCES.ARSC
RESOURCES.ARSC
RESOURCES.ARSC
RESOURCES.ARSC
RESOURCES.ARSC
RESOURCES.ARSC
android {
…
defaultConfig {
resConfigs „pl”, „en”
}
}
19MB vs
APK RAW SIZE #5
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
Shrinked resources
19MB vs
APK RAW SIZE #5
+ Fixed list of configurations
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
Shrinked resources
19MB vs
17MB
APK RAW SIZE #5
+ Fixed list of configurations
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
Shrinked resources
19MB vs
17MB
10%
reduction
APK RAW SIZE #5
+ Fixed list of configurations
Graphics optimizations
Removed all mdpi
Removed all but xxxhdpi for large gfx

Switched toVD
Reusing icons
Shrinked resources
TODAY
vs
mid 2016 vs today
APK RAW SIZE
vs
73%
reduction
mid 2016 vs today
APK RAW SIZE
APK SPLIT
XXXHDPI XXHDPI
XHDPI HDPI
APK
APK SPLIT
XXXHDPI XXHDPI XHDPI HDPI
APK APK APKAPK
PROTIPS
PROTIPS
• Optimize your graphics
PROTIPS
• Optimize your graphics
• Use any tool you choose
PROTIPS
• Optimize your graphics
• Use any tool you choose
• Experiment with PNG/JPEG/WebP
PROTIPS
• Optimize your graphics
• Use any tool you choose
• Experiment with PNG/JPEG/WebP
• Switch doVD
PROTIPS
• Optimize your graphics
• Use any tool you choose
• Experiment with PNG/JPEG/WebP
• Switch doVD
•Start playing with APK Analyzer
SEE ALSO
SEE ALSO
• Colt McAnlis (Google)
• #perfMatters videos onYouTube
• „Image compression for Android dev” video from Google I/O 2016
• Articles on Medium
SEE ALSO
• Colt McAnlis (Google)
• #perfMatters videos onYouTube
• „Image compression for Android dev” video from Google I/O 2016
• Articles on Medium
• Wojtek Kaliciński (Google)
• „Put your app on diet” video from Google I/O 2016
• #SmallerAPK articles on Medium
Mateusz
Grzechociński
Jacek
Karaśkiewicz
THANKYOU!
@j_karaskiewicz@mgrzechocinski
Mateusz
Grzechociński
Jacek
Karaśkiewicz
THANKYOU!
@j_karaskiewicz@mgrzechocinski

Save users' data!