Currently, I'm having experience that, a piece of code, which makes use of Google Drive API is running fine without introducing ProGuard.
However, after introducing ProGuard, I'm getting the following run-time error.
at java.lang.Thread.run(Thread.java:856) Caused by: java.lang.NullPointerException at com.google.api.client.util.Types.getActualParameterAtPosition(Types.java:329) at com.google.api.client.util.Types.getIterableParameter(Types.java:309) at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:546) at com.google.api.client.json.JsonParser.parse(JsonParser.java:350) at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:586) at com.google.api.client.json.JsonParser.parse(JsonParser.java:289) at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:76) at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:71) at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:491) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:456) at com.jstock.c.b.a(CloudFile.java:136)
Note, the crash happens at my code (which is com.jstock.c.b.a if I retrace using mapping.txt)
// request is Files.List FileList files = request.execute();
In my proguard, I thought having the following 2 key instructions, able to prevent the crash from happen : I tell ProGuard never touch on jackson and Google libraries.
-keep class org.codehaus.** { *; } -keep class com.google.** { *; } -keep interface org.codehaus.** { *; } -keep interface com.google.** { *; }
But that doesn't work. NPE still happen at Types.java
Note that, I had another try is that, I thought obfuscate process causes NPE happens. Hence, I try to disable it using -dontobfuscate
. But this time, I will not able to generate APK file, and getting a popular error message : Conversion to Dalvik format failed with error 1
Here is the proguard configuration which causes NPE at Google Drive API.
-optimizationpasses 1 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # Comment out the following line, will cause popular "Conversion to Dalvik format failed with error 1" ##-dontobfuscate -dontwarn sun.misc.Unsafe -dontwarn com.google.common.collect.MinMaxPriorityQueue -dontwarn javax.swing.** -dontwarn java.awt.** -dontwarn org.jasypt.encryption.pbe.** -dontwarn java.beans.** -dontwarn org.joda.time.** -dontwarn com.google.android.gms.** -dontwarn org.w3c.dom.bootstrap.** -dontwarn com.ibm.icu.text.** -dontwarn demo.** # Hold onto the mapping.text file, it can be used to unobfuscate stack traces in the developer console using the retrace tool -printmapping mapping.txt # Keep line numbers so they appear in the stack trace of the develeper console -keepattributes *Annotation*,EnclosingMethod,SourceFile,LineNumberTable -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService -keep class android.support.v4.app.** { *; } -keep interface android.support.v4.app.** { *; } -keep class com.actionbarsherlock.** { *; } -keep interface com.actionbarsherlock.** { *; } # https://sourceforge.net/p/proguard/discussion/182456/thread/e4d73acf -keep class org.codehaus.** { *; } -keep class com.google.** { *; } -keep interface org.codehaus.** { *; } -keep interface com.google.** { *; } -assumenosideeffects class android.util.Log { public static int d(...); public static int i(...); public static int e(...); public static int v(...); } -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } -assumenosideeffects class android.util.Log { public static *** d(...); public static *** v(...); public static *** i(...); } -keepclasseswithmembers class com.google.common.base.internal.Finalizer{ <methods>; }
Is there anything else I can try?
I'm not sure it might be caused by the combination of the libraries. (Although things run pretty well without introducing ProGuard)
If I look at the NPE crash location (Types.getActualParameterAtPosition(Types.java:329))
private static Type getActualParameterAtPosition(Type type, Class<?> superClass, int position) { ParameterizedType parameterizedType = Types.getSuperParameterizedType(type, superClass); Type valueType = parameterizedType.getActualTypeArguments()[position]; // this is normally a type variable, except in the case where the class of iterableType is // superClass, e.g. Iterable<String> if (valueType instanceof TypeVariable<?>) { Type resolve = Types.resolveTypeVariable(Arrays.asList(type), (TypeVariable<?>) valueType); if (resolve != null) { return resolve; } } return valueType; }
I suspect Types.getSuperParameterizedType
returning null
. So, I further look into Types.getSuperParameterizedType
.
public static ParameterizedType getSuperParameterizedType(Type type, Class<?> superClass) { if (type instanceof Class<?> || type instanceof ParameterizedType) { outer: while (type != null && type != Object.class) { Class<?> rawType; if (type instanceof Class<?>) { // type is a class rawType = (Class<?>) type; } else { // current is a parameterized type ParameterizedType parameterizedType = (ParameterizedType) type; rawType = getRawClass(parameterizedType); // check if found Collection if (rawType == superClass) { // return the actual collection parameter return parameterizedType; } if (superClass.isInterface()) { for (Type interfaceType : rawType.getGenericInterfaces()) { // interface type is class or parameterized type Class<?> interfaceClass = interfaceType instanceof Class<?> ? (Class<?>) interfaceType : getRawClass( (ParameterizedType) interfaceType); if (superClass.isAssignableFrom(interfaceClass)) { type = interfaceType; continue outer; } } } } // move on to the super class type = rawType.getGenericSuperclass(); } } return null; }
What is the possible root cause that may cause getSuperParameterizedType
returning null
, after processed by ProGuard?
A combination of the following has worked for me:
-keep class com.google.** { *;} -keep interface com.google.** { *;} -dontwarn com.google.** -dontwarn sun.misc.Unsafe -dontwarn com.google.common.collect.MinMaxPriorityQueue -keepattributes *Annotation*,Signature -keep class * extends com.google.api.client.json.GenericJson { *; } -keep class com.google.api.services.drive.** { *; }
This provided a working proguard compatible solution for a recent Google Drive project.
Cannot take all credit for this solution though, originally found at this link here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With