La API de Google Drive no funciona bien con ProGuard (NPE)

Actualmente, tengo experiencia en que una pieza de código que hace uso de la API de Google Drive funciona bien sin la introducción de ProGuard.

Sin embargo, después de presentar ProGuard, recibo el siguiente error de tiempo de ejecución.

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.cba(CloudFile.java:136) 

Tenga en cuenta que el locking ocurre en mi código (que es com.jstock.cba si vuelvo a usar mapeo.txt)

 // request is Files.List FileList files = request.execute(); 

En mi defensa, pensé en tener las siguientes 2 instrucciones clave, capaces de evitar que ocurriera el locking: le digo a ProGuard que nunca toque las bibliotecas de jackson y Google.

 -keep class org.codehaus.** { *; } -keep class com.google.** { *; } -keep interface org.codehaus.** { *; } -keep interface com.google.** { *; } 

Pero eso no funciona. NPE todavía ocurre en Types.java

Tenga en cuenta que, tuve otra oportunidad es que, pensé que el proceso de ofuscación causa la NPE. Por lo tanto, bash desactivarlo usando -dontobfuscate . Pero esta vez, no podré generar archivos APK y obtener un mensaje de error popular: la conversión a formato Dalvik falló con el error 1

Aquí está la configuración proguard que causa NPE en 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 ; } -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public (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{ ; } 

¿Hay algo más que pueda probar?

No estoy seguro de que pueda ser causado por la combinación de las bibliotecas. (Aunque las cosas funcionan bastante bien sin la introducción de ProGuard)

enter image description here

Si miro la ubicación del locking de NPE (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, eg Iterable if (valueType instanceof TypeVariable) { Type resolve = Types.resolveTypeVariable(Arrays.asList(type), (TypeVariable) valueType); if (resolve != null) { return resolve; } } return valueType; } 

Sospecho que Types.getSuperParameterizedType devuelve null . Entonces, investigo más en 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; } 

¿Cuál es la posible causa raíz que puede hacer que getSuperParameterizedType devuelva null , después de procesado por ProGuard?

Una combinación de lo siguiente me ha funcionado:

 -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.** { *; } 

Esto proporcionó una solución compatible proguard de trabajo para un proyecto reciente de Google Drive.

No se puede tomar todo el crédito por esta solución, originalmente encontrada en este enlace aquí

La combinación adecuada es:

-keepattributes Firma, RuntimeVisibleAnnotations, AnnotationDefault

Hay una configuración proguard preparada por Google para el proyecto google-api-java-client

https://github.com/google/google-api-java-client/blob/57fe35766cbba0a0d5a9a296be81468d730a29f8/google-api-client-assembly/proguard-google-api-client.txt

Primero, mantener una clase no significa no tocarlo. Significa no cambiar su nombre, y usarlo como base para determinar si otras clases no están referenciadas y pueden ser eliminadas.

La optimización todavía ocurre, que probablemente sea su problema. El siguiente paso que haría sería intentar con: -dontoptimize

Esto debería causar que sus otras optimizaciones sean ignoradas.

Por cierto, no estoy seguro de qué versión de SDK estás usando. Estoy usando 15, 20 es lo último, y se crea un archivo proguard-project.txt con el proyecto. Las opciones de optimización que utiliza son:

 -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* 

Si desactivar la optimización lo hace funcionar, quizás desactivar todas las optimizaciones (¡eso es qué!) Hace el SDK, también le permitirá optimizar.

El método Types.getSuperParameterizedType se basa en información sobre generics. Los generics se borran en Java. El comstackdor solo los agrega como atributos de anotación, la JVM los ignora y ProGuard los descarta a menos que le diga que no lo haga. Entonces esto podría ayudar:

 -keepattributes *Annotation* 

¿su código usa algo que implemente Serializable? Todos ellos deben ser excluidos también.

Ha habido pocas actualizaciones de GooglePlayServices últimamente. No me gusta la nueva API. Tenía los mismos problemas.

No pude comstackr la aplicación firmada con proguard. La plantilla Proguard de Google no funcionó para mí.

Agregué estas cuatro líneas a mi configuración proguard y está funcionando:

 -dontwarn com.google.android.gms.** -keep interface com.google.** { *; } -keep class * extends com.google.api.client.json.GenericJson {*;} -keep class com.google.api.services.drive.** {*;} 

Esto es extraño. Versión anterior de google-api-services-drive-v2 comstackda sin ningún problema.

Estoy usando la última versión en este momento: google-api-services-drive-v2-rev47-1.12.0-beta.jar