$ g assembleDebug
Total time: 1.908 secs
$ du -h ./app-debug.apk
24K ./app-debug.apk
Slide 7
Slide 7 text
dependencies {
compile ‘google-play-services'
}
Slide 8
Slide 8 text
$ g assembleDebug
Total time: 3.014 secs
$ du -h ./app-debug.apk
1.8M ./app-debug.apk
Slide 9
Slide 9 text
$ g assembleDebug
Total time: 3.014 secs
$ du -h ./app-debug.apk
1.8M ./app-debug.apk
$ tar -xzvf app-debug.apk
$ du -h -d 0 classes.dex res
3.8M classes.dex
592K res
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 48.784 secs
Slide 19
Slide 19 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 48.784 secs
$ du -h ./app-debug.apk
7.5M ./app-debug.apk
Slide 20
Slide 20 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 48.784 secs
$ du -h ./app-debug.apk
7.5M ./app-debug.apk
$ dexcount ./app-debug.apk
Total method count: 81986
Slide 21
Slide 21 text
@Override
protected void attachBaseContext(Context c) {
super.attachBaseContext(c);
MultiDex.install(this);
}
Slide 22
Slide 22 text
@Override
protected void attachBaseContext(Context c) {
super.attachBaseContext(c);
long start = System.currentTimeMillis();
MultiDex.install(this);
long end = System.currentTimeMillis();
long elapsed = end - start;
Log.d(TAG, “multidex: " + elapsed + "ms");
}
Slide 23
Slide 23 text
@Override
protected void attachBaseContext(Context c) {
super.attachBaseContext(c);
long start = System.currentTimeMillis();
MultiDex.install(this);
long end = System.currentTimeMillis();
long elapsed = end - start;
Log.d(TAG, “multidex: " + elapsed + "ms");
}
252ms on Samsung S5 with KitKat at 66k methods
Slide 24
Slide 24 text
@Override
protected void attachBaseContext(Context c) {
super.attachBaseContext(c);
long start = System.currentTimeMillis();
MultiDex.install(this);
long end = System.currentTimeMillis();
long elapsed = end - start;
Log.d(TAG, “multidex: " + elapsed + "ms");
}
1083ms on Samsung S5 with KitKat at 81k methods
Slide 25
Slide 25 text
@Override
protected void attachBaseContext(Context c) {
super.attachBaseContext(c);
long start = System.currentTimeMillis();
MultiDex.install(this);
long end = System.currentTimeMillis();
long elapsed = end - start;
Log.d(TAG, “multidex: " + elapsed + "ms");
}
~4000ms on Nexus 5 with KitKat at ~130k methods
Slide 26
Slide 26 text
@Override
protected void attachBaseContext(Context c) {
super.attachBaseContext(c);
long start = System.currentTimeMillis();
MultiDex.install(this);
long end = System.currentTimeMillis();
long elapsed = end - start;
Log.d(TAG, “multidex: " + elapsed + "ms");
}
2ms on Nexus 5 with Lollipop at 81k methods
$ANDROID_HOME/tools/proguard/proguard-android.txt
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
+-keepnames class * implements android.os.Parcelable {
+ public static final ** CREATOR;
Slide 37
Slide 37 text
$ANDROID_HOME/tools/proguard/proguard-android.txt
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
+-keepnames class * implements android.os.Parcelable {
+ public static final ** CREATOR;
“OK ProGuard, please keep all Parcelables”
Slide 38
Slide 38 text
$ANDROID_HOME/tools/proguard/proguard-android.txt
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
+-keepnames class * implements android.os.Parcelable {
+ public static final ** CREATOR;
“OK ProGuard, please keep all *USED* Parcelables”
Slide 39
Slide 39 text
$ANDROID_HOME/tools/proguard/proguard-android.txt
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
+-keepnames class * implements android.os.Parcelable {
+ public static final ** CREATOR;
http://proguard.sourceforge.net/manual/usage.html
Slide 40
Slide 40 text
buildTypes {
all {
minifyEnabled true
proguardFiles ‘copypasta-rules.pro'
}
}
AndroidRuntime D Shutting down VM
E FATAL EXCEPTION: main
E Process: org.chalup.proguardtechtalk, PID: 21061
E java.lang.RuntimeException: Unable to start activity ComponentInfo{…}:
java.lang.NullPointerException:
E at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
E at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
E at android.app.ActivityThread.access$800(ActivityThread.java:144)
E at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
E at android.os.Handler.dispatchMessage(Handler.java:102)
E at android.os.Looper.loop(Looper.java:135)
E at android.app.ActivityThread.main(ActivityThread.java:5221)
E at java.lang.reflect.Method.invoke(Native Method)
E at java.lang.reflect.Method.invoke(Method.java:372)
E at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
E at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
E Caused by: java.lang.NullPointerException:
E at org.chalup.proguardtechtalk.MainActivity.onCreate(Unknown Source)
E at android.app.Activity.performCreate(Activity.java:5933)
E at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
E at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
E ... 10 more
Slide 58
Slide 58 text
+-dontwarn butterknife.internal.**
+-keep class **$$ViewInjector {
+ *;
+}
+-keepnames class * {
+ @butterknife.InjectView *;
+}
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 16.096 secs
Slide 68
Slide 68 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 16.096 secs
$ du -h ./app-debug.apk
3.5M ./app-debug.apk
Slide 69
Slide 69 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 16.096 secs
$ du -h ./app-debug.apk
3.5M ./app-debug.apk
$ dexcount ./app-debug.apk
Total method count: 6636
Slide 70
Slide 70 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 48.784 secs
$ du -h ./app-debug.apk
7.5M ./app-debug.apk
$ dexcount ./app-debug.apk
android.support.v4: 81986
Slide 71
Slide 71 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 16.096 secs
$ du -h ./app-debug.apk
3.5M ./app-debug.apk
$ dexcount ./app-debug.apk
Total method count: 6636
Slide 72
Slide 72 text
- multiDexEnabled true
Slide 73
Slide 73 text
$ g assembleDebug
BUILD SUCCESSFUL
Total time: 15.049 secs
$ du -h ./app-debug.apk
3.5M ./app-debug.apk
$ dexcount ./app-debug.apk
Total method count: 6539
Slide 74
Slide 74 text
TAKEAWAY #6
Good ProGuard config FTW!
Slide 75
Slide 75 text
GOTCHA #1
Slide 76
Slide 76 text
-dontobfuscate -dontoptimize
$ g assembleDebug
BUILD SUCCESSFUL
Slide 77
Slide 77 text
# -dontobfuscate -dontoptimize
$ g assembleDebug
BUILD SUCCESSFUL
Slide 78
Slide 78 text
-dontobfuscate
$ g assembleDebug
:app:dexDebug FAILED
EXCEPTION FROM SIMULATION:
local variable type mismatch: Ph'nglui mglw’nafh
Cthulhu R'lyeh wgah'nagl fhtagn
-dontobfuscate
-optimizations !code/allocation/variable
$ g assembleDebug
BUILD SUCCESSFUL
Slide 81
Slide 81 text
http://stackoverflow.com/a/7587680/184953
-dontobfuscate
-optimizations !code/allocation/variable
$ g assembleDebug
BUILD SUCCESSFUL
Slide 82
Slide 82 text
GOTCHA #2
Slide 83
Slide 83 text
LinkedHashMultimap map =
LinkedHashMultimap.create();
map.put(1, "1");
map.put(1, "2");
map.put(1, "3");
Collection data =
map.asMap().get(1);
Log.d("JCH", new Gson().toJson(data));
Slide 84
Slide 84 text
E FATAL EXCEPTION: main
E Process: org.chalup.proguardtechtalk, PID: 31243
E java.lang.reflect.GenericSignatureFormatError
E at libcore.reflect.GenericSignatureParser.expect(GenericSignatureParser.java:473)
E at libcore.reflect.GenericSignatureParser.parseClassTypeSignature(GenericSignatureParser.java:332)
E at libcore.reflect.GenericSignatureParser.parseClassSignature(GenericSignatureParser.java:234)
E at libcore.reflect.GenericSignatureParser.parseForClass(GenericSignatureParser.java:126)
E at java.lang.Class.getGenericInterfaces(Class.java:1134)
E at com.google.gson.internal.$Gson$Types.getGenericSupertype($Gson$Types.java:238)
E at com.google.gson.internal.$Gson$Types.getSupertype($Gson$Types.java:269)
E at com.google.gson.internal.$Gson$Types.getCollectionElementType($Gson$Types.java:288)
E at com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:51)
E at com.google.gson.Gson.getAdapter(Gson.java:359)
E at com.google.gson.Gson.toJson(Gson.java:592)
E at com.google.gson.Gson.toJson(Gson.java:579)
E at com.google.gson.Gson.toJson(Gson.java:534)
E at com.google.gson.Gson.toJson(Gson.java:514)
E at org.chalup.proguardtechtalk.MainActivity.getString(MainActivity.java:40)
E at org.chalup.proguardtechtalk.MainActivity.onCreate(MainActivity.java:36)
E at android.app.Activity.performCreate(Activity.java:5933)
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.1'
}
configurations.all {
resolutionStrategy {
force 'net.sf.proguard:proguard-gradle:4.11'
}
}
}
NOTE: this is top level build.gradle, not module one
Slide 88
Slide 88 text
GOTCHA #3
Slide 89
Slide 89 text
# Release ProGuard config
-assumenosideeffects class
android.util.Log {
public static *** d(...);
}