Shrinking WhatsApp

Shrinking WhatsApp

Billions of people in over 180 countries use WhatsApp to stay in touch with friends and family. At WhatsApp we relentlessly work on shrinking our apk as much as possible given that many of our users live in regions with poor connectivity and we are committed to leave no one behind. In this session we will cover some of the wins, regressions, strategies and technologies that we use to tame WhatApp's apk size.

Conference: https://www.droidcon.sg
Video: coming soon

61aff7d05db638357b5c04bcb164d1c3?s=128

Evelio Tarazona Cáceres

July 18, 2019
Tweet

Transcript

  1. Evelio Tarazona Cáceres Engineering Manager Shrinking
 WhatsApp

  2. None
  3. None
  4. https://www.youtube.com/watch?v=8PW3O2mqTn8

  5. We focus on building a simple, private and secure messaging

    service that works fast and reliably anywhere in the world.
  6. https://www.youtube.com/watch?v=erDF7IoiHpo

  7. Simple, Reliable, Secure Messaging WhatsApp is widely used on Android

    devices. 
 As we add new features to the product, 
 we must continue supporting it in older devices.
  8. Simplicity

  9. Keep it small

  10. Fewer features

  11. Keep the app size small

  12. WhatsAppSize?

  13. download apk universal build

  14. https://www.reddit.com/r/MapPorn/comments/7gnuuk/world_map_of_average_internet_connection_speed/

  15. download apk install universal build

  16. keeping an eye on it

  17. None
  18. None
  19. None
  20. None
  21. delivery

  22. None
  23. None
  24. https://developer.android.com/platform/technology/app-bundle

  25. Dynamic Delivery https://android-developers.googleblog.com/2018/05/io-2018-everything-new-in-google-play.html

  26. End-to-end encryption

  27. https://developer.android.com/platform/technology/app-bundle

  28. If you are okay with giving your key to Google,

    you can use app bundles.
  29. So what do we do?

  30. Keep the apk size small

  31. And do not share our signing key with anyone

  32. apk splits

  33. splits {
 density {
 enable true
 include "ldpi", "mdpi", "hdpi",

    "xhdpi", "xxhdpi", "xxxhdpi"
 }
 
 
 
 } // apk splits by density
  34. Reduction of: ~1-2 MB per density split vs universal apk

  35. splits {
 density {
 enable true
 include "ldpi", "mdpi", "hdpi",

    "xhdpi", "xxhdpi", "xxxhdpi"
 }
 abi { enable true include "armeabi-v7a", "arm64-v8a", "x86", "x86_64" } } // apk splits by density & abi
  36. Reduction of: ~10-12 MB per abi split vs universal apk

  37. At the cost of release management complexities

  38. YMMV

  39. Optimizations

  40. WhatsAnAPK?

  41. It's a zip file

  42. Not all files in the apk are compressed

  43. There is also zip metadata like timestamps

  44. Repackaging and stripping metadata ~1MB reduction

  45. ➜ unzip -v your.apk | grep -E ' 0%'

  46. ➜ apksigner USAGE: apksigner <command> [options] apksigner --version apksigner --help

    EXAMPLE: apksigner sign --ks release.jks app.apk apksigner verify --verbose app.apk apksigner is a tool for signing Android APK files and for checking whether signatures of APK files will verify on Android devices. # built-in tooling
  47. ➜ zipalign Zip alignment utility Copyright (C) 2009 The Android

    Open Source Project Usage: zipalign [-f] [-p] [-v] [-z] <align> infile.zip outfile.zip zipalign -c [-p] [-v] <align> infile.zip <align>: alignment in bytes, e.g. '4' provides 32-bit alig -c: check alignment only (does not modify file) -f: overwrite existing outfile.zip -p: memory page alignment for stored shared object files # built-in tooling
  48. WhatsInAnAPK?

  49. ➜ unzip whatsapp.apk

  50. ➜ ls AndroidManifest.xml assets lib resources.arsc META-INF classes.dex res

  51. remove stuff

  52. None
  53. configurations { packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' exclude 'com/google/android/search/verification/client/R.java'

    exclude 'third_party/java_src/error_prone/project/annotations/Annotations.gwt.xml' exclude 'third_party/java_src/error_prone/project/annotations/Google_internal.gwt.xml' exclude 'jsr305_annotations/Jsr305_annotations.gwt.xml' exclude 'error_prone/Annotations.gwt.xml' exclude 'protobuf.meta' exclude 'build-data.properties' exclude 'androidsupportmultidexversion.txt' // ... // This saved us ~300KB // packagingOptions - exclude
  54. res

  55. res/layout/preferences.xml: Warning: The resource R.layout.preferences appears to be unused [UnusedResources]

    # lint, enable UnusedResources
  56. android {
 buildTypes {
 release { // ... shrinkResources true


    
 } 
 }
 } // built-in optimizations
  57. aaptOptions { cruncherEnabled [false|true] } # optimize pngs

  58. ➜ optipng ➜ pngcrush ➜ zopflipng ➜ advpng # zopflipng

    reduced png bloat by ~2MB # can't use webp because API level support, use it if you can # do use svg for some assets # vector drawable not used extensively enough # optimize pngs
  59. android {
 defaultConfig {
 resConfigs "en", ”es", "fr”, // …


    }
 } // Removing strings for unsupported languages
 // saved us ~1MB. // remove unused configs
  60. strings

  61. String pool: "My App", "Hello", "Exit", "Settings", "Feature" Default config:

    string/myapp 0x00000001 string/hello 0x00000002 string/exit 0x00000003 string/settings 0x00000004 string/feature 0x00000005 ========== Config size: 20 bytes resources.arsc https://medium.com/androiddevelopers/smallerapk-part-3-removing-unused-resources-1511f9e3f761
  62. String pool: "My App", "Hello", "Exit", "Settings", "Feature", "New feature"

    Default config: -v21 config: string/myapp 0x00000001 string/hello 0x00000002 string/exit 0x00000003 string/settings 0x00000004 string/feature 0x00000005 ========== Config size: 20 bytes resources.arsc https://medium.com/androiddevelopers/smallerapk-part-3-removing-unused-resources-1511f9e3f761
  63. String pool: "My App", "Hello", "Exit", "Settings", "Feature", "New feature"

    Default config: -v21 config: string/myapp 0x00000001 NO_ENTRY string/hello 0x00000002 NO_ENTRY string/exit 0x00000003 NO_ENTRY string/settings 0x00000004 NO_ENTRY string/feature 0x00000005 0x00000006 ========== ========== Config size: 20 bytes 20 bytes! resources.arsc https://medium.com/androiddevelopers/smallerapk-part-3-removing-unused-resources-1511f9e3f761
  64. 4 bytes * 3500 null entries * 50 languages =

    700 kilobytes resources.arsc https://medium.com/androiddevelopers/smallerapk-part-3-removing-unused-resources-1511f9e3f761
  65. alternatives: in code? other format? resources.arsc https://medium.com/androiddevelopers/smallerapk-part-3-removing-unused-resources-1511f9e3f761

  66. None
  67. None
  68. stringpacks saved us ~8MB

  69. bytecode

  70. single dex app

  71. ➜ ls AndroidManifest.xml assets lib resources.arsc META-INF classes.dex res

  72. dependencies { implementation // ... debugImplementation // ... // ...

    // watch & limit your dependencies
  73. android {
 buildTypes {
 release { // ... shrinkResources true


    minifyEnabled true
 } 
 }
 } // built-in optimizations
  74. android {
 buildTypes {
 release { // ... shrinkResources true


    minifyEnabled true
 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'config/proguard-rules-release.pro' } 
 }
 } // built-in optimizations
  75. android {
 buildTypes {
 release { // ... shrinkResources true


    minifyEnabled true
 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'config/proguard-rules-release.pro' } 
 }
 } // built-in optimizations
  76. android {
 buildTypes {
 release { // ... shrinkResources true


    minifyEnabled true
 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'config/proguard-rules-release.pro' } 
 }
 } // built-in optimizations
  77. android.enableR8=true // we observed an increase of ~168KB // but

    a reduction on method reference count // and an improvement on cold start // some people on the community observed regressions R8
  78. Method references count for consumer beta (pre-redex) 55000 81200 107400

    133600 159800 186000 Debug Release/Proguard Release/R8 71,296 90,725 185,674 64K
  79. redex

  80. https://fbredex.com

  81. ➜ redex your.apk -o your-optimized.apk -c config.json

  82. { "redex" : { "passes" : [ "ReBindRefsPass", "BridgePass", "SynthPass",

    "FinalInlinePass", "DelSuperPass", "SingleImplPass", "MethodInlinePass", "StaticReloPass", "RemoveEmptyClassesPass", "ShortenSrcStringsPass" ] } } sample redex config
  83. Method references count for consumer beta release 55000 81200 107400

    133600 159800 186000 Unoptimized Proguard Proguard + Redex R8 R8 + Redex 61,640 71,296 66,778 90,725 185,674 64K
  84. • Better Proguard/R8 configuration • Additional redex passes • Downloadable

    assets: emoji, stringpacks, other res. • Dynamic Features • Keyframes/VectorDrawables/WebP/basis universal • Work on install and download size • Native library optimizations: 
 noCompress vs. xz compress Future Work
  85. Thanks!

  86. Q&A @eveliotc 
 https://evel.io

  87. None