ProGuard
ProGuard is an open-source tool to optimize APK's so that they take less space and run slightly faster. It can also help obfsucating code, but only slightly, according to their landing page. After integrating Crashlytics, I enabled ProGuard. Crashlytics was incredibly useful for investigating the resulting crashes I got.
Enabling ProGuard
You can enable ProGuard by setting "Minify Enabled" to true in the Module Settings window:
Enabling it in the GUI simply adds the following lines to the gradle file:
android {
...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
...
}
}
}
After compiling again, the APK size went from 3.6 MB to 2.4 MB. Nice! However after pushing a release to alpha and running that build, the app crashed and I got the following report in my Crashlytics dashboard:
Fatal Exception: com.google.firebase.database.d: No properties to serialize found on class com.wafrat.rappel.a.a
at com.google.android.gms.internal.zzdzs.(Unknown Source)
at com.google.android.gms.internal.zzdzr.zzbm(Unknown Source)
at com.google.android.gms.internal.zzdzr.zza(Unknown Source)
at com.google.android.gms.internal.zzdzr.zzbm(Unknown Source)
at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
at com.wafrat.rappel.ScrollingActivity$listenToReminders$1.invoke(Unknown Source)
Keeping debug info for crash reports
I could kind of guess what was going on, but in the future it would be better to have the source file name and the line that triggers the exception. The Crashlytics documentation on ProGuard explains how to do so. You add those lines to proguard-rules.pro
:
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
Now the same exception generates a report that says it got triggered from ScrollingActivity at line 72:
Fatal Exception: com.google.firebase.database.d: No properties to serialize found on class com.wafrat.rappel.a.a
at com.google.android.gms.internal.zzdzs.(Unknown Source)
at com.google.android.gms.internal.zzdzr.zzbm(Unknown Source)
at com.google.android.gms.internal.zzdzr.zza(Unknown Source)
at com.google.android.gms.internal.zzdzr.zzbm(Unknown Source)
at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
at com.wafrat.rappel.ScrollingActivity$listenToReminders$1.invoke(ScrollingActivity.kt:72)
Fixing ProGuard for Firebase Database
What happens is that the fields and methods in our data classes have been renamed. So when Firebase Database tries to deserialize data, the deserialize methods are not found. I first configured ProGuard by keeping some members in classes that implemented Serializable: Proguard for Serializable classes, but it did not work. It turns out I should use Firebase Database's suggested settings that keep all members for all of my data classes:
-keepattributes Signature
-keepclassmembers class com.wafrat.rappel.data.** {
*;
}