Fighting application size with ProGuard and beyond Eric Lafortune

Transcription

Fighting application size with ProGuard and beyond Eric Lafortune
Fighting application size
with ProGuard and beyond
Eric Lafortune
Developer of ProGuard and DexGuard
Technical director at Saikoa
www.saikoa.com
Applications
App
Resources
Dalvik
bytecode
Assets
Native
code
Renderscript
code
Technical constraints
Google Play Store: max 50 MB
App
Resources
Dalvik
bytecode
Assets
Native
code
Renderscript
code
Dex format: max 65536 method IDs
Froyo/Gingerbread: 5 MB LinearAlloc buffer
Android build process
Android build process
Assets
Assets
XML resources
Application
Java source
Aapt
Javac
Application
Java bytecode
Dex
Libraries
Java bytecode
Compiled
XML resources
Libraries
Java bytecode
Dalvik bytecode
Compress media
●
Images: JPEG (lossy)
●
Images: PNG
aapt crunch -S input_dir -C output_dir
●
Audio: AAC
●
Video: H264 AVC
Remove unused resources
●
Lint (Android SDK)
gradle lint
●
android-resource-remover (Philipp Berner)
●
android-unused-resources (S. Kennedy)
Splitting apk files
Splitting apk files
Assets
Assets
Assets
XML resources
Application
Java source
Aapt
Javac
Compiled
XML resources
Application
Java bytecode
Dex
Libraries
Java bytecode
Compiled
XML resources
Libraries
Java bytecode
Dalvik bytecode
Dalvik bytecode
Splitting apk files
●
Different variants in Gradle:
android
android {{
...
...
productFlavors
productFlavors {{
flavor1
flavor1 {{
ignoreAssetsPattern
ignoreAssetsPattern '!*_large.png'
'!*_large.png'
assets.srcDirs
assets.srcDirs == ['assets1']
['assets1']
res.srcDirs
== ['res1']
res.srcDirs
['res1']
}}
}}
}}
flavor2
flavor2 {{
ignoreAssetsPattern
ignoreAssetsPattern '!*_small.png'
'!*_small.png'
assets.srcDirs
=
['assets2']
assets.srcDirs = ['assets2']
res.srcDirs
== ['res2']
res.srcDirs
['res2']
}}
Splitting apk files
●
Splits in Gradle:
android
android {{
...
splits {
density
density {{
enable
enable true
reset()
reset()
include
include 'mdpi', 'hdpi', 'xhdpi'
}}
}
}
abi
abi {
enable
enable true
reset()
reset()
include
include 'armeabi-v7a', 'x86', 'mips'
'mips'
}}
Code size
Code size
Assets
Assets
java.lang.IllegalArgumentException:
XML resources method ID not in [0, 0xffff]: 65536
Application
Java source
Javac
Aapt
Application
Java bytecode
Dex
Libraries
Java bytecode
Compiled
XML resources
Libraries
Java bytecode
Dalvik bytecode
Dex file
Strings
Types
Prototypes
Field IDs
Method IDs
Class definitions
...
Method IDs
#0: Accounts . <init>(.....)
#1: AccountManager . get(......)
#2: AccountManager . …..
#3: …..
#4: …..
...
...
...
...
...
...
...
...
...
...
...
...
...
...
#65535: …..
ProGuard
Application
code
Shrink
Optimize
Obfuscate
Processed
code
Libraries
Android
runtime
Android
runtime
ProGuard
Assets
Assets
XML resources
Application
Java source
Aapt
Javac
Application
Java bytecode
ProGuard
Libraries
Java bytecode
Compiled
XML resources
Libraries
Java bytecode
Processed
Java bytecode
Dex
Dalvik bytecode
Example configuration: Dagger
-keepclassmembers,allowobfuscation
-keepclassmembers,allowobfuscation class
class ** {{
@dagger.**
@dagger.** <fields>;
<fields>;
@dagger.**
<methods>;
@dagger.** <methods>;
}}
-keep
-keep
-keep
-keep
-keep
-keep
class
class
class
class
class
class
Generated classes
**$$ModuleAdapter
**$$ModuleAdapter
**$$InjectAdapter
**$$InjectAdapter
**$$StaticInjection
**$$StaticInjection
-keep
-keep class
class com.example.DemoModule
com.example.DemoModule
-keep
-keep class
class com.example.AndroidModule
com.example.AndroidModule
-keep
-keep class
class com.example.HomeActivity
com.example.HomeActivity
-keepnames
-keepnames class
class dagger.Lazy
dagger.Lazy
Corresponding base classes
Libraries
Library
Google Play Services
Guava
Method IDs
6.0
14,495
15.0
Yahoo Flurry Ads
Facebook
8,511
4.1.0
ActionBarSherlock
RoboGuice
23,607
4.4.0
4,300
2.0
3,787
3.5.2
3,166
Yahoo Flurry Analytics
Scala Core
2.11.2
4.1.0
1,148
50,786
ProGuard on libraries
Library
Java bytecode
ProGuard
Processed library
Java bytecode
Shrink Ads library
configuration.txt
-injars
-injars
-outjars
-outjars
google-play-services.jar
google-play-services.jar
google-play-services-ads.jar
google-play-services-ads.jar
-libraryjars
-libraryjars
-libraryjars
-libraryjars
android-sdk/extras/android/support/v4/android-support-v4.jar
android-sdk/platforms/android-20/android.jar
-dontoptimize
-dontoptimize
-dontobfuscate
-dontobfuscate
-dontwarn
-dontwarn com.google.**.R
-dontwarn
-dontwarn com.google.**.R$*
-dontnote
-dontnote
-keep
-keep public
public class
class com.google.android.gms.ads.** {
public
public protected
protected *;
}}
-keep
-keep class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
java.lang.String NULL;
}}
Command line:
proguard
proguard @@ configuration.txt
configuration.txt
Shrink Ads library
Google Play
Services
library
ProGuard
Ads library
Before
After
Reduction
Size
3.3 M
578 K
83 %
Classes
3294
497
85 %
Method IDs
23607
3751
84 %
Shrink Maps library
-injars
-injars
-outjars
-outjars
google-play-services.jar
google-play-services.jar
google-play-services-maps.jar
google-play-services-maps.jar
-libraryjars
-libraryjars
-libraryjars
-libraryjars
android-sdk/extras/android/support/v4/android-support-v4.jar
android-sdk/platforms/android-20/android.jar
-dontoptimize
-dontoptimize
-dontobfuscate
-dontobfuscate
-dontwarn
-dontwarn com.google.**.R
-dontwarn
-dontwarn com.google.**.R$*
-dontnote
-dontnote
-keep
-keep public
public class
class com.google.android.gms.maps.**,
com.google.android.gms.common.**,
com.google.android.gms.common.**,
com.google.android.gms.location.**
com.google.android.gms.location.** {
public
public protected
protected *;
}}
-keep
-keep class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
java.lang.String NULL;
}}
proguard
proguard @@ configuration.txt
configuration.txt
Shrink Maps library
Google Play
Services
library
ProGuard
Maps library
Before
After
Reduction
Size
3.3 M
583 K
82 %
Classes
3294
546
83 %
Method IDs
23607
4891
79 %
Splitting dex files
Main dex file
Secondary
dex file
Build-time
Run-time
Splitting dex files
Assets
Assets
XML resources
Application
Java source
Libraries
Java bytecode
Aapt
Javac
Compiled
XML resources
Application
Java bytecode
Dex
Main
Dalvik bytecode
Libraries
Java bytecode
Dex
Secondary
Dalvik bytecode
Dex splitting: tools
●
secondary-dex-gradle (Mohit Kanwal)
●
Dex 65536 (Mmin18)
●
DexGuard (Saikoa)
●
Android 5.0 / android.support.multidex
Dex splitting: secondary-dex-gradle
●
●
ApplicationProject
LibraryProject
settings.gradle
include
include ':ApplicationProject',
':ApplicationProject', ':LibraryProject'
':LibraryProject'
●
AndroidManifest.xml
<application
<application
android:name="com.example.App"
android:name="com.example.App"
...
... >>
●
AppProject/src/com/example/App.java
AppProject/src/com/example/SecondaryDex.java
AppProject/src/com/example/FrameworkHack.java
Dex splitting: secondary-dex-gradle
Advantages:
●
It works!
Disadvantages:
●
Split project
●
No references library → application
●
Dex classpath hack
Dex splitting: Dex 65536
●
libs/google-play-services.jar (for example)
●
custom_rules.xml
...
...
<pathtool
<pathtool
libs="libs/google-play-services.jar"
libs="libs/google-play-services.jar"
...
... />
/>
...
...
●
AndroidManifest.xml
<application
<application
android:name="com.example.App"
android:name="com.example.App"
...
... >>
●
src/com/example/App.java
new
new DexClassLoader(dexFile.getAbsolutePath(),
DexClassLoader(dexFile.getAbsolutePath(),
dexOpt.getAbsolutePath(),
nativeLibraryDir,
classLoader.getParent());
Dex splitting: Dex 65536
Advantages:
●
It works!
Disadvantages:
●
Only for library jars
●
Dex classloader hack
Dex splitting: DexGuard
●
Gradle, Ant, Eclipse, Maven, Android Studio,...
●
dexguard-project.txt
-splitdexfile com.google.**
com.google.**
-splitdexfile !com.facebook.samples.**,
!com.facebook.samples.**, com.facebook.**
com.facebook.**
Dex splitting: DexGuard
Advantages:
●
Transparent
●
Flexible
●
Lazy loading
Disadvantages:
●
Reflection
Dex splitting: Android 5.0
Android 5.0 loads classes2.dex, classes3.dex, etc.
●
build.gradle
...
...
dx.additionalParameters
dx.additionalParameters +=
+= '--multi-dex'
'--multi-dex'
dx.additionalParameters
dx.additionalParameters +=
+=
"--main-dex-list=$projectDir/list.txt".toString()
"--main-dex-list=$projectDir/list.txt".toString()
●
list.txt
com/example/SomeClass.class
com/example/SomeClass.class
...
...
●
AndroidManifest.xml (for legacy platforms)
<application
<application
android:name="android.support.multidex.MultiDexApplication"
android:name="android.support.multidex.MultiDexApplication"
...
... >>
Dex splitting: Android 5.0
Advantages:
●
Latest standard
Disadvantages:
●
Eager loading
Summary
Resources and assets:
–
Compress
–
Trim
–
Split apk
Bytecode:
–
Shrink libraries
–
Shrink application
–
Split dex file
Further reading
●
“Custom Class Loading in Dalvik”, Fred Chung, Google
http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html
●
“Play Services 5.0 Is A Monolith Abomination”, Jake Wharton
http://jakewharton.com/play-services-is-a-monolith/
●
“DEX Sky’s the limit? No, 65K methods is”, Sebastiano Gottardo
https://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71
●
“Multi-dex to rescue from the infamous 65536 methods limit”, Alex Lipov
http://blog.osom.info/2014/10/multi-dex-to-rescue-from-infamous-65536.html
●
“Under the Hood: Dalvik patch for Facebook for Android”, David Reiss
https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920
●
“Tips for reducing APK file size”, David Karlsson, Sony
http://developer.sonymobile.com/2012/01/31/tips-for-reducing-apk-file-size/
Software tools
●
android-resource-remover, Philipp Berner, KeepSafe
https://github.com/KeepSafe/android-resource-remover
●
android-unused-resources, S. Kennedy
https://code.google.com/p/android-unused-resources/
●
secondary-dex-gradle, Mohit Kanwal
https://github.com/creativepsyco/secondary-dex-gradle
●
Dex 65536, Mmin18
https://github.com/mmin18/Dex65536
●
ProGuard
http://proguard.sourceforge.net/
●
DexGuard
http://www.saikoa.com/dexguard
Questions?
Open source
ProGuard
Optimization
Shrinking
Saikoa
Java bytecode
DexGuard
Dalvik bytecode

Similar documents