在启用混淆器的情况下使用 GSON
Using GSON with proguard enabled
我的代码在没有 proguard 的情况下工作得很好,但是当启用 proguard 时 GSON 不工作。
这是代码中不起作用的部分
JSONArray mensaje = response.getJSONArray("categorias");
// Parsear con Gson
Categorias[] categorias = gson.fromJson(mensaje.toString(), Categorias[].class);
Log.d("mainfragment","desc categoria "+categorias[0].getDescripcionCategoria());
mainfragment 的日志打印 null
# Output
D/Dato categorias﹕ Respuesta: {"categorias":[{"idCategoria":"22","imagenCategoria":"ic_aseguradora","descripcionCategoria":"Aseguradoras"},{"idCategoria":"24","imagenCategoria":"ic_bar","descripcionCategoria":"Bares"},{"idCategoria":"12","imagenCategoria":"ic_boutique","descripcionCategoria":"Boutiques"},{"idCategoria":"6","imagenCategoria":"ic_cafe","descripcionCategoria":"Cafeterias"},{"idCategoria":"21","imagenCategoria":"ic_ciber","descripcionCategoria":"Ciber"},{"idCategoria":"10","imagenCategoria":"ic_estetica","descripcionCategoria":"Estéticas"},{"idCategoria":"1","imagenCategoria":"ic_farmacia","descripcionCategoria":"Farmacias"},{"idCategoria":"7","imagenCategoria":"ic_ferreteria","descripcionCategoria":"Ferreterias"},{"idCategoria":"16","imagenCategoria":"ic_gas","descripcionCategoria":"Gas"},{"idCategoria":"23","imagenCategoria":"ic_gasolinera","descripcionCategoria":"Gasolineras"},{"idCategoria":"4","imagenCategoria":"ic_gym","descripcionCategoria":"Gimnasios"},{"idCategoria":"2","imagenCategoria":"ic_hotel","descripcionCategoria":"Hoteles"},{"idCategoria":"15","imagenCategoria":"ic_lavanderia","descripcionCategoria":"Lavanderias"},{"idCategoria":"19","imagenCategoria":"ic_muebleria","descripcionCategoria":"Mueblerias"},{"idCategoria":"25","imagenCategoria":"ic_optica","descripcionCategoria":"Ópticas"},{"idCategoria":"20","imagenCategoria":"ic_pasteleria","descripcionCategoria":"Pastelerias"},{"idCategoria":"17","imagenCategoria":"ic_pizza","descripcionCategoria":"Pizzerías"},{"idCategoria":"13","imagenCategoria":"ic_purificadora","descripcionCategoria":"Purificadoras de agua"},{"idCategoria":"5","imagenCategoria":"ic_restaurant","descripcionCategoria":"Restaurantes"},{"idCategoria":"11","imagenCategoria":"ic_ropa","descripcionCategoria":"Ropa"},{"idCategoria":"9","imagenCategoria":"ic_salon","descripcionCategoria":"Salones de fiestas"},{"idCategoria":"3","imagenCategoria":"ic_sonido","descripcionCategoria":"Sonidos"},{"idCategoria":"28","imagenCategoria":"ic_taqueria","descripcionCategoria":"Taquería"},{"idCategoria":"8","imagenCategoria":"ic_taxi","descripcionCategoria":"Taxis"},{"idCategoria":"14","imagenCategoria":"ic_tortilleria","descripcionCategoria":"Tortillerias"},{"idCategoria":"27","imagenCategoria":"ic_veterinaria","descripcionCategoria":"Veterinarias"},{"idCategoria":"18","imagenCategoria":"ic_vinateria","descripcionCategoria":"Vinaterías"},{"idCategoria":"26","imagenCategoria":"ic_zapateria","descripcionCategoria":"Zapaterías"}],"estado":1}
D/mainfragment﹕ desc categoria null
这是我的混淆规则
#GoogleMaps
-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@ccom.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
#Volley?
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-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
-dontnote com.android.vending.licensing.ILicensingService
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-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 **.R$* {
public static <fields>;
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * {
public protected *;
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keep class android.support.v7.widget.SearchView
-keep class android.support.v7.widget.**{*;}
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
-keep class com.android.volley.** { *; }
-keep interface com.android.volley.** { *; }
-keepattributes *Annotation*
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
#-keepattributes *Annotation*
-keepattributes EnclosingMethod
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class Categorias.data.model.** { *; }
-keep class Categorias.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.puertosoft.appcomercialdelpuerto.android.model.** { *; }
-keep class com.puertosoft.appcomercialdelpuerto.model.** { *; }
-keep class com.puertosoft.appcomercialdelpuerto.model.User { *; }
# Add the gson class
-keep public class com.google.gson
# Add any classes the interact with gson
-keep class com.puertosoft.appcomercialdelpuerto.models.ChatModel { *; }
-keep class com.puertosoft.appcomercialdelpuerto.models.FeedModel { *; }
-keep class com.puertosoft.appcomercialdelpuerto.android.models.ChatModel { *; }
-keep class com.puertosoft.appcomercialdelpuerto.android.models.FeedModel { *; }
-libraryjars /build/intermediates/pre-dexed/debug/gson-2.3-08958b96da94c86264ec30e35a9d524bac95d2df.jar
-printmapping outputfile.txt
-renamesourcefileattribute SourceFile
#-keepattributes SourceFile,LineNumberTable
这是受影响的class
public class Categorias {
private String idCategoria;
private String descripcionCategoria;
private String imagenCategoria;
public Categorias(String idCategoria, String descripcionCategoria, String imagenCategoria){
this.idCategoria=idCategoria;
this.descripcionCategoria=descripcionCategoria;
this.imagenCategoria=imagenCategoria;
}
public String getIdCategoria(){
return idCategoria;
}
public String getDescripcionCategoria(){
return descripcionCategoria;
}
public String getImagenCategoria(){
return imagenCategoria;
}
}
当您将 proguard 脚本应用于您的模型时 类 它会混淆它们的名称和属性的名称。所以在混淆 String descripcionCategoria;
之后你会得到类似 String aaaa;
的东西
Gson 通过 java 反射工作,它会在解析数据时尝试使用 属性 名称。因此,在对模型应用混淆后 类 您将无法解析您的数据。
因此,从混淆器脚本中排除模型 类,您将能够再次解析。
您需要排除混淆您的模型 类 如下所示,我排除了所有模型 类在包裹 in.intellicode.webservices.models
中
-keep class in.intellicode.webservices.models.** { *; }
-keep class in.intellicode.models.** { *; }
-keep class in.intellicode.events.*{ *; }
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
变量名会被 proguard 混淆,给你留下类似
的东西
private String a;
而不是
private String descripcionCategoria;
您可以添加 proguard 规则,这样一些 classes 就不会被混淆。我用这些逃脱了它:
-keepattributes Signature
# POJOs used with GSON
# The variable names are JSON key values and should not be obfuscated
-keepclassmembers class com.example.apps.android.Categorias { <fields>; }
# You can apply the rule to all the affected classes also
# -keepclassmembers class com.example.apps.android.model.** { <fields>; }
如果您的 POJO class 名称也用于解析,那么您还应该添加规则
-keep class com.example.apps.android.model.** { <fields>; }
在你的情况下,没有使用注释,如果你这样做,你将需要它
# Keep the annotations
-keepattributes *Annotation*
解决此问题的另一种方法 是使用 SerializedName
注释并混淆 class。为此,您仍然需要 -keepattributes *Annotation*
规则。
import com.google.gson.annotations.SerializedName
@SerializedName("descripcionCategoria")
private String descripcionCategoria;
如果您希望您的模型仍然被混淆,请使用注释 @SerializedName("name_of_json_field")
。它会让gson知道字段的真实名称。
相信你也会需要
-keepattributes *Annotation*
防止您的注释混淆
改变这个
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
这对我有用
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
在您应用的 build.gradle 文件中。
仅供参考,
https://developer.android.com/studio/build/shrink-code
使用 Gson
默认规则中的 proguard-rules
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
来源:https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg
我的代码在没有 proguard 的情况下工作得很好,但是当启用 proguard 时 GSON 不工作。
这是代码中不起作用的部分
JSONArray mensaje = response.getJSONArray("categorias");
// Parsear con Gson
Categorias[] categorias = gson.fromJson(mensaje.toString(), Categorias[].class);
Log.d("mainfragment","desc categoria "+categorias[0].getDescripcionCategoria());
mainfragment 的日志打印 null
# Output
D/Dato categorias﹕ Respuesta: {"categorias":[{"idCategoria":"22","imagenCategoria":"ic_aseguradora","descripcionCategoria":"Aseguradoras"},{"idCategoria":"24","imagenCategoria":"ic_bar","descripcionCategoria":"Bares"},{"idCategoria":"12","imagenCategoria":"ic_boutique","descripcionCategoria":"Boutiques"},{"idCategoria":"6","imagenCategoria":"ic_cafe","descripcionCategoria":"Cafeterias"},{"idCategoria":"21","imagenCategoria":"ic_ciber","descripcionCategoria":"Ciber"},{"idCategoria":"10","imagenCategoria":"ic_estetica","descripcionCategoria":"Estéticas"},{"idCategoria":"1","imagenCategoria":"ic_farmacia","descripcionCategoria":"Farmacias"},{"idCategoria":"7","imagenCategoria":"ic_ferreteria","descripcionCategoria":"Ferreterias"},{"idCategoria":"16","imagenCategoria":"ic_gas","descripcionCategoria":"Gas"},{"idCategoria":"23","imagenCategoria":"ic_gasolinera","descripcionCategoria":"Gasolineras"},{"idCategoria":"4","imagenCategoria":"ic_gym","descripcionCategoria":"Gimnasios"},{"idCategoria":"2","imagenCategoria":"ic_hotel","descripcionCategoria":"Hoteles"},{"idCategoria":"15","imagenCategoria":"ic_lavanderia","descripcionCategoria":"Lavanderias"},{"idCategoria":"19","imagenCategoria":"ic_muebleria","descripcionCategoria":"Mueblerias"},{"idCategoria":"25","imagenCategoria":"ic_optica","descripcionCategoria":"Ópticas"},{"idCategoria":"20","imagenCategoria":"ic_pasteleria","descripcionCategoria":"Pastelerias"},{"idCategoria":"17","imagenCategoria":"ic_pizza","descripcionCategoria":"Pizzerías"},{"idCategoria":"13","imagenCategoria":"ic_purificadora","descripcionCategoria":"Purificadoras de agua"},{"idCategoria":"5","imagenCategoria":"ic_restaurant","descripcionCategoria":"Restaurantes"},{"idCategoria":"11","imagenCategoria":"ic_ropa","descripcionCategoria":"Ropa"},{"idCategoria":"9","imagenCategoria":"ic_salon","descripcionCategoria":"Salones de fiestas"},{"idCategoria":"3","imagenCategoria":"ic_sonido","descripcionCategoria":"Sonidos"},{"idCategoria":"28","imagenCategoria":"ic_taqueria","descripcionCategoria":"Taquería"},{"idCategoria":"8","imagenCategoria":"ic_taxi","descripcionCategoria":"Taxis"},{"idCategoria":"14","imagenCategoria":"ic_tortilleria","descripcionCategoria":"Tortillerias"},{"idCategoria":"27","imagenCategoria":"ic_veterinaria","descripcionCategoria":"Veterinarias"},{"idCategoria":"18","imagenCategoria":"ic_vinateria","descripcionCategoria":"Vinaterías"},{"idCategoria":"26","imagenCategoria":"ic_zapateria","descripcionCategoria":"Zapaterías"}],"estado":1}
D/mainfragment﹕ desc categoria null
这是我的混淆规则
#GoogleMaps
-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@ccom.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
#Volley?
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-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
-dontnote com.android.vending.licensing.ILicensingService
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-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 **.R$* {
public static <fields>;
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * {
public protected *;
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keep class android.support.v7.widget.SearchView
-keep class android.support.v7.widget.**{*;}
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
-keep class com.android.volley.** { *; }
-keep interface com.android.volley.** { *; }
-keepattributes *Annotation*
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
#-keepattributes *Annotation*
-keepattributes EnclosingMethod
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class Categorias.data.model.** { *; }
-keep class Categorias.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.puertosoft.appcomercialdelpuerto.android.model.** { *; }
-keep class com.puertosoft.appcomercialdelpuerto.model.** { *; }
-keep class com.puertosoft.appcomercialdelpuerto.model.User { *; }
# Add the gson class
-keep public class com.google.gson
# Add any classes the interact with gson
-keep class com.puertosoft.appcomercialdelpuerto.models.ChatModel { *; }
-keep class com.puertosoft.appcomercialdelpuerto.models.FeedModel { *; }
-keep class com.puertosoft.appcomercialdelpuerto.android.models.ChatModel { *; }
-keep class com.puertosoft.appcomercialdelpuerto.android.models.FeedModel { *; }
-libraryjars /build/intermediates/pre-dexed/debug/gson-2.3-08958b96da94c86264ec30e35a9d524bac95d2df.jar
-printmapping outputfile.txt
-renamesourcefileattribute SourceFile
#-keepattributes SourceFile,LineNumberTable
这是受影响的class
public class Categorias {
private String idCategoria;
private String descripcionCategoria;
private String imagenCategoria;
public Categorias(String idCategoria, String descripcionCategoria, String imagenCategoria){
this.idCategoria=idCategoria;
this.descripcionCategoria=descripcionCategoria;
this.imagenCategoria=imagenCategoria;
}
public String getIdCategoria(){
return idCategoria;
}
public String getDescripcionCategoria(){
return descripcionCategoria;
}
public String getImagenCategoria(){
return imagenCategoria;
}
}
当您将 proguard 脚本应用于您的模型时 类 它会混淆它们的名称和属性的名称。所以在混淆 String descripcionCategoria;
之后你会得到类似 String aaaa;
Gson 通过 java 反射工作,它会在解析数据时尝试使用 属性 名称。因此,在对模型应用混淆后 类 您将无法解析您的数据。
因此,从混淆器脚本中排除模型 类,您将能够再次解析。
您需要排除混淆您的模型 类 如下所示,我排除了所有模型 类在包裹 in.intellicode.webservices.models
中-keep class in.intellicode.webservices.models.** { *; }
-keep class in.intellicode.models.** { *; }
-keep class in.intellicode.events.*{ *; }
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
变量名会被 proguard 混淆,给你留下类似
的东西private String a;
而不是
private String descripcionCategoria;
您可以添加 proguard 规则,这样一些 classes 就不会被混淆。我用这些逃脱了它:
-keepattributes Signature
# POJOs used with GSON
# The variable names are JSON key values and should not be obfuscated
-keepclassmembers class com.example.apps.android.Categorias { <fields>; }
# You can apply the rule to all the affected classes also
# -keepclassmembers class com.example.apps.android.model.** { <fields>; }
如果您的 POJO class 名称也用于解析,那么您还应该添加规则
-keep class com.example.apps.android.model.** { <fields>; }
在你的情况下,没有使用注释,如果你这样做,你将需要它
# Keep the annotations
-keepattributes *Annotation*
解决此问题的另一种方法 是使用 SerializedName
注释并混淆 class。为此,您仍然需要 -keepattributes *Annotation*
规则。
import com.google.gson.annotations.SerializedName
@SerializedName("descripcionCategoria")
private String descripcionCategoria;
如果您希望您的模型仍然被混淆,请使用注释 @SerializedName("name_of_json_field")
。它会让gson知道字段的真实名称。
相信你也会需要
-keepattributes *Annotation*
防止您的注释混淆
改变这个
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
这对我有用
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
在您应用的 build.gradle 文件中。
仅供参考, https://developer.android.com/studio/build/shrink-code
使用 Gson
默认规则中的 proguard-rules
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
来源:https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg