eric lafortune - fighting application size with proguard and beyond
TRANSCRIPT
![Page 1: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/1.jpg)
Fighting application size
with ProGuard and beyond
Eric LafortuneDeveloper of ProGuard and DexGuard
Technical director at Saikoawww.saikoa.com
![Page 2: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/2.jpg)
Applications
Dalvikbytecode
Resources Assets
Nativecode
Renderscriptcode
App
![Page 3: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/3.jpg)
Dalvikbytecode
Resources Assets
Nativecode
Renderscriptcode
Technical constraints
AppGoogle Play Store: max 50 MB
Froyo/Gingerbread: 5 MB LinearAlloc buffer
Dex format: max 65536 method IDs
![Page 4: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/4.jpg)
Android build process
![Page 5: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/5.jpg)
Android build process
ApplicationJava bytecode
LibrariesJava bytecode
Dex Dalvik bytecode
JavacApplicationJava source
LibrariesJava bytecode
XML resources
Assets Assets
CompiledXML resourcesAapt
![Page 6: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/6.jpg)
Compress media
● Images: JPEG (lossy)
● Images: PNG
● Audio: AAC
● Video: H264 AVC
aapt crunch -S input_dir -C output_diraapt crunch -S input_dir -C output_dir
![Page 7: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/7.jpg)
Remove unused resources
● Lint (Android SDK)
● android-resource-remover (Philipp Berner)
● android-unused-resources (S. Kennedy)
● Gradle (Android SDK)
gradle lintgradle lint
android { buildTypes { release { minifyEnabled true shrinkResources true } }}
android { buildTypes { release { minifyEnabled true shrinkResources true } }}
![Page 8: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/8.jpg)
Splitting apk files
![Page 9: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/9.jpg)
Splitting apk files
ApplicationJava bytecode
LibrariesJava bytecode
Dex Dalvik bytecode
JavacApplicationJava source
LibrariesJava bytecode
XML resources
AssetsAssets
CompiledXML resourcesAapt
Dalvik bytecode
Assets
CompiledXML resources
![Page 10: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/10.jpg)
Splitting apk files
● Different variants in Gradle:android { ... productFlavors {
flavor1 { ignoreAssetsPattern '!*_large.png' assets.srcDirs = ['assets1'] res.srcDirs = ['res1'] }
flavor2 { ignoreAssetsPattern '!*_small.png' assets.srcDirs = ['assets2'] res.srcDirs = ['res2'] } }}
android { ... productFlavors {
flavor1 { ignoreAssetsPattern '!*_large.png' assets.srcDirs = ['assets1'] res.srcDirs = ['res1'] }
flavor2 { ignoreAssetsPattern '!*_small.png' assets.srcDirs = ['assets2'] res.srcDirs = ['res2'] } }}
![Page 11: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/11.jpg)
Splitting apk files
● Splits in Gradle:android { ... splits {
density { enable true reset() include 'mdpi', 'hdpi', 'xhdpi' }
abi { enable true reset() include 'armeabi-v7a', 'x86', 'mips' } }}
android { ... splits {
density { enable true reset() include 'mdpi', 'hdpi', 'xhdpi' }
abi { enable true reset() include 'armeabi-v7a', 'x86', 'mips' } }}
![Page 12: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/12.jpg)
Code size
![Page 13: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/13.jpg)
Code size
ApplicationJava bytecode
LibrariesJava bytecode
Dex Dalvik bytecode
JavacApplicationJava source
LibrariesJava bytecode
XML resources
Assets Assets
CompiledXML resourcesAapt
java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536
![Page 14: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/14.jpg)
Dex file
...
Strings
Types
Prototypes
Field IDs
Method IDs
Class definitions
Method IDs#0: Accounts . <init>(.....)#1: AccountManager . get(......)#2: AccountManager . …..#3: …..#4: …............................................#65535: …..
![Page 15: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/15.jpg)
ProGuard
Shrink
Androidruntime
Optimize Obfuscate
Androidruntime
Libraries
Applicationcode
Processedcode
![Page 16: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/16.jpg)
ProGuard
ApplicationJava bytecode
ProGuard
LibrariesJava bytecode
ProcessedJava bytecode Dex
JavacApplicationJava source
LibrariesJava bytecode
XML resources
Assets Assets
CompiledXML resourcesAapt
Dalvik bytecode
![Page 17: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/17.jpg)
-keepclassmembers,allowobfuscation class * { @dagger.** <fields>; @dagger.** <methods>;}
-keep class **$$ModuleAdapter-keep class **$$InjectAdapter-keep class **$$StaticInjection
-keep class com.example.DemoModule-keep class com.example.AndroidModule-keep class com.example.HomeActivity
-keepnames class dagger.Lazy
-keepclassmembers,allowobfuscation class * { @dagger.** <fields>; @dagger.** <methods>;}
-keep class **$$ModuleAdapter-keep class **$$InjectAdapter-keep class **$$StaticInjection
-keep class com.example.DemoModule-keep class com.example.AndroidModule-keep class com.example.HomeActivity
-keepnames class dagger.Lazy
Example configuration: Dagger
Generated classes
Corresponding base classes
![Page 18: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/18.jpg)
Libraries
Library Method IDs
Google Play Services 6.0 23,607
Guava 15.0 14,495
Yahoo Flurry Ads 4.1.0 8,511
ActionBarSherlock 4.4.0 4,300
RoboGuice 2.0 3,787
Facebook 3.5.2 3,166
Yahoo Flurry Analytics 4.1.0 1,148
Scala Core 2.11.2 50,786
![Page 19: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/19.jpg)
ProGuard on libraries
ProGuard
LibraryJava bytecode
Processed libraryJava bytecode
![Page 20: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/20.jpg)
Shrink Ads library-injars google-play-services.jar-outjars google-play-services-ads.jar
-libraryjars android-sdk/extras/android/support/v4/android-support-v4.jar-libraryjars android-sdk/platforms/android-20/android.jar
-dontoptimize-dontobfuscate-dontwarn com.google.**.R-dontwarn com.google.**.R$*-dontnote
-keep public class com.google.android.gms.ads.** { public protected *;}
-keep class com.google.android.gms.common.internal.safeparcel.SafeParcelable { java.lang.String NULL;}
-injars google-play-services.jar-outjars google-play-services-ads.jar
-libraryjars android-sdk/extras/android/support/v4/android-support-v4.jar-libraryjars android-sdk/platforms/android-20/android.jar
-dontoptimize-dontobfuscate-dontwarn com.google.**.R-dontwarn com.google.**.R$*-dontnote
-keep public class com.google.android.gms.ads.** { public protected *;}
-keep class com.google.android.gms.common.internal.safeparcel.SafeParcelable { java.lang.String NULL;}
proguard @ configuration.txtproguard @ configuration.txt
Command line:
configuration.txt
![Page 21: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/21.jpg)
Shrink Ads library
Before After Reduction
Size 3.3 M 578 K 83 %
Classes 3294 497 85 %
Method IDs 23607 3751 84 %
ProGuard
Google PlayServiceslibrary
Ads library
![Page 22: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/22.jpg)
Shrink Maps library-injars google-play-services.jar-outjars google-play-services-maps.jar
-libraryjars android-sdk/extras/android/support/v4/android-support-v4.jar-libraryjars android-sdk/platforms/android-20/android.jar
-dontoptimize-dontobfuscate-dontwarn com.google.**.R-dontwarn com.google.**.R$*-dontnote
-keep public class com.google.android.gms.maps.**, com.google.android.gms.common.**, com.google.android.gms.location.** { public protected *;}
-keep class com.google.android.gms.common.internal.safeparcel.SafeParcelable { java.lang.String NULL;}
-injars google-play-services.jar-outjars google-play-services-maps.jar
-libraryjars android-sdk/extras/android/support/v4/android-support-v4.jar-libraryjars android-sdk/platforms/android-20/android.jar
-dontoptimize-dontobfuscate-dontwarn com.google.**.R-dontwarn com.google.**.R$*-dontnote
-keep public class com.google.android.gms.maps.**, com.google.android.gms.common.**, com.google.android.gms.location.** { public protected *;}
-keep class com.google.android.gms.common.internal.safeparcel.SafeParcelable { java.lang.String NULL;}
proguard @ configuration.txtproguard @ configuration.txt
![Page 23: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/23.jpg)
Shrink Maps library
Before After Reduction
Size 3.3 M 583 K 82 %
Classes 3294 546 83 %
Method IDs 23607 4891 79 %
ProGuard
Google PlayServiceslibrary
Maps library
![Page 24: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/24.jpg)
Splitting dex files
Main dex file
Secondarydex file
Build-time Run-time
![Page 25: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/25.jpg)
Splitting dex files
ApplicationJava bytecode
LibrariesJava bytecode
DexMain
Dalvik bytecodeJavacApplicationJava source
LibrariesJava bytecode
XML resources
Assets Assets
CompiledXML resourcesAapt
SecondaryDalvik bytecode
Dex
![Page 26: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/26.jpg)
Dex splitting: tools
● secondary-dex-gradle (Mohit Kanwal)
● Dex 65536 (Mmin18)
● DexGuard (Saikoa)
● multiDex (Android Gradle plugin 0.14)
![Page 27: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/27.jpg)
Dex splitting: secondary-dex-gradle
● ApplicationProjectLibraryProject
● settings.gradle
● AndroidManifest.xml
● AppProject/src/com/example/App.javaAppProject/src/com/example/SecondaryDex.javaAppProject/src/com/example/FrameworkHack.java
include ':ApplicationProject', ':LibraryProject'include ':ApplicationProject', ':LibraryProject'
<application android:name="com.example.App" ... >
<application android:name="com.example.App" ... >
![Page 28: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/28.jpg)
Dex splitting: secondary-dex-gradle
Advantages:
● It works!
Disadvantages:
● Split project
● No references library application→
● Dex classpath hack
![Page 29: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/29.jpg)
Dex splitting: Dex 65536
● libs/google-play-services.jar (for example)
● custom_rules.xml
● AndroidManifest.xml
● src/com/example/App.java
... <pathtool libs="libs/google-play-services.jar" ... /> ...
... <pathtool libs="libs/google-play-services.jar" ... /> ...
<application android:name="com.example.App" ... >
<application android:name="com.example.App" ... >
new DexClassLoader(dexFile.getAbsolutePath(), dexOpt.getAbsolutePath(), nativeLibraryDir, classLoader.getParent());
new DexClassLoader(dexFile.getAbsolutePath(), dexOpt.getAbsolutePath(), nativeLibraryDir, classLoader.getParent());
![Page 30: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/30.jpg)
Dex splitting: Dex 65536
Advantages:
● It works!
Disadvantages:
● Only for library jars
● Dex classloader hack
![Page 31: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/31.jpg)
Dex splitting: DexGuard
● Gradle, Ant, Eclipse, Maven, Android Studio,...
● dexguard-project.txt
-splitdexfile com.google.**
-splitdexfile !com.facebook.samples.**, com.facebook.**
-splitdexfile com.google.**
-splitdexfile !com.facebook.samples.**, com.facebook.**
![Page 32: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/32.jpg)
Dex splitting: DexGuard
Advantages:
● Transparent
● Flexible
● Lazy loading
Disadvantages:
● Reflection
![Page 33: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/33.jpg)
Dex splitting: multiDex
Android 5.0 loads classes2.dex, classes3.dex, etc.
● build.gradle
● AndroidManifest.xml (for legacy platforms)
dependencies { compile 'com.android.support:multidex:1.0.0'}
android { ... defaultConfig { multiDexEnabled true }}
dependencies { compile 'com.android.support:multidex:1.0.0'}
android { ... defaultConfig { multiDexEnabled true }}
<application android:name="android.support.multidex.MultiDexApplication" ... >
<application android:name="android.support.multidex.MultiDexApplication" ... >
![Page 34: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/34.jpg)
Dex splitting: Android 5.0
Advantages:
● Latest standard
Disadvantages:
● Eager loading
![Page 35: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/35.jpg)
Summary
Resources and assets:
– Compress
– Trim
– Split apk
Bytecode:
– Shrink libraries
– Shrink application
– Split dex file
![Page 36: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/36.jpg)
Further reading
● “Custom Class Loading in Dalvik”, Fred Chung, Googlehttp://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html
● “Play Services 5.0 Is A Monolith Abomination”, Jake Whartonhttp://jakewharton.com/play-services-is-a-monolith/
● “DEX Sky’s the limit? No, 65K methods is”, Sebastiano Gottardohttps://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71
● “Multi-dex support”, Xavier Ducrohethttps://plus.google.com/+XavierDucrohet/posts/1FnzwdcBnyC
● “Under the Hood: Dalvik patch for Facebook for Android”, David Reisshttps://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920
● “Remove unused resources”, Tor Norbyehttps://plus.google.com/+TorNorbye/posts/eHsStybrrBf
● “Tips for reducing APK file size”, David Karlsson, Sonyhttp://developer.sonymobile.com/2012/01/31/tips-for-reducing-apk-file-size/
![Page 37: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/37.jpg)
Software tools
● android-resource-remover, Philipp Berner, KeepSafehttps://github.com/KeepSafe/android-resource-remover
● android-unused-resources, S. Kennedyhttps://code.google.com/p/android-unused-resources/
● secondary-dex-gradle, Mohit Kanwalhttps://github.com/creativepsyco/secondary-dex-gradle
● Dex 65536, Mmin18https://github.com/mmin18/Dex65536
● ProGuardhttp://proguard.sourceforge.net/
● DexGuardhttp://www.saikoa.com/dexguard
![Page 38: Eric Lafortune - Fighting application size with ProGuard and beyond](https://reader031.vdocuments.us/reader031/viewer/2022030300/5881bb1b1a28abdd348b78e9/html5/thumbnails/38.jpg)
Questions?
Open source
Java bytecode
ProGuard
Saikoa
DexGuard
Dalvik bytecode
Shrinking
Optimization