Proguard和Object扩展了Parcelable - 在解组时找不到类

时间:2014-09-10 16:02:08

标签: android proguard parcelable

我发布了我的apk。在调试模式下,我没有错误。 当我用Proguard签署我的apk时,我的应用程序工作直到第四个屏幕,我必须处理实现Parcelable的值对象类

 E/Parcel(811): Class not found when unmarshalling: com.spg.movil.vo.Pdv
 E/Parcel(811): java.lang.ClassNotFoundException: com.spg.movil.vo.Pdv
 E/Parcel(811): at java.lang.Class.classForName(Native Method)
 E/Parcel(811): at java.lang.Class.forName(Class.java:251)
 E/Parcel(811): at java.lang.Class.forName(Class.java:216)
 E/Parcel(811): at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
 E/Parcel(811): at android.os.Parcel.readParcelable(Parcel.java:2097)
 E/Parcel(811): at android.os.Parcel.readValue(Parcel.java:2013)
 E/Parcel(811): at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
 E/Parcel(811): at android.os.Bundle.unparcel(Bundle.java:249)
 E/Parcel(811): at android.os.Bundle.getString(Bundle.java:1118)
 E/Parcel(811): at android.content.Intent.getStringExtra(Intent.java:4991)
 E/Parcel(811): at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1353)
 E/Parcel(811): at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:977)
 E/Parcel(811): at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3936)
 E/Parcel(811): at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3839)
 E/Parcel(811): at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
 E/Parcel(811): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2546)
 E/Parcel(811): at android.os.Binder.execTransact(Binder.java:404)
 E/Parcel(811): at dalvik.system.NativeStart.run(Native Method)
 E/Parcel(811): Caused by: java.lang.NoClassDefFoundError: com/spg/movil/vo/Pdv
 E/Parcel(811): ... 18 more
 E/Parcel(811): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.spg.movil.vo.Pdv" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
 E/Parcel(811): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67)
 E/Parcel(811): at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
 E/Parcel(811): at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
 E/Parcel(811): ... 18 more

这是我的VO课程:

public class Pdv implements Parcelable {

int id;
int clientId;
String canal;
String formato;
String ciudad;
String region;
int ndeterminante;
String sucursal;
int nielsen;
String tienda;
String calle;
String colonia;
int CP;
int activo;
String cadena;
int estadoId;
String estado;

double latitude;
double longitude;
String telefono;
String contacto;
String horarioIni;
String horarioFin;

Proyecto proyecto;
int idRuta;
int done;
int sincronizado;

// Not include in parcelable
Marker marker;

public Marker getMarker() {
    return marker;
}

public void setMarker(Marker marker) {
    this.marker = marker;
}



@Override
public int describeContents() {
    return 0;
}


public Pdv(int id, int clientId, String canal, String formato, String ciudad, String region, int ndeterminante,
        String sucursal, int nielsen, String tienda, String calle, String colonia, int cP, int activo,
        double latitude, double longitude, String telefono, String contacto, String horarioIni, String horarioFin,
        Proyecto proyecto, int done, int sincronizado, String cadena, String estado) {
    super();
    this.id = id;
    this.clientId = clientId;
    this.canal = canal;
    this.formato = formato;
    this.ciudad = ciudad;
    this.region = region;
    this.ndeterminante = ndeterminante;
    this.sucursal = sucursal;
    this.nielsen = nielsen;
    this.tienda = tienda;
    this.calle = calle;
    this.colonia = colonia;
    this.CP = cP;
    this.cadena = cadena;
    this.estado = estado;
    this.activo = activo;
    this.latitude = latitude;
    this.longitude = longitude;
    this.telefono = telefono;
    this.contacto = contacto;
    this.horarioIni = horarioIni;
    this.horarioFin = horarioFin;
    this.proyecto = proyecto;
    this.done = done;
    this.sincronizado = sincronizado;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(id);
    dest.writeInt(clientId);
    dest.writeString(canal);
    dest.writeString(formato);
    dest.writeString(ciudad);
    dest.writeString(region);
    dest.writeInt(ndeterminante);
    dest.writeString(sucursal);
    dest.writeInt(nielsen);
    dest.writeString(tienda);
    dest.writeString(calle);
    dest.writeString(colonia);
    dest.writeString(cadena);
    dest.writeString(estado);
    dest.writeInt(estadoId);
    dest.writeInt(CP);
    dest.writeInt(activo);
    dest.writeInt(done);
    dest.writeInt(sincronizado);
    dest.writeInt(idRuta);
    dest.writeDouble(latitude);
    dest.writeDouble(longitude);
    dest.writeString(telefono);
    dest.writeString(contacto);
    dest.writeString(horarioIni);
    dest.writeString(horarioFin);
    dest.writeParcelable(proyecto, 0);

}

public static final Parcelable.Creator<Pdv> CREATOR = new Parcelable.Creator<Pdv>() {
    @Override
    public Pdv createFromParcel(Parcel source) {
        return new Pdv(source);
    }

    @Override
    public Pdv[] newArray(int size) {
        return new Pdv[size];
    }
};

public Pdv(Parcel in) {


    this.id = in.readInt();
    this.clientId = in.readInt();
    this.canal = in.readString();
    this.formato = in.readString();
    this.ciudad = in.readString();
    this.region = in.readString();
    this.ndeterminante = in.readInt();
    this.sucursal = in.readString();
    this.nielsen = in.readInt();
    this.tienda = in.readString();
    this.calle = in.readString();
    this.colonia = in.readString();
    this.cadena = in.readString();
    this.estado = in.readString();
    this.estadoId = in.readInt();
    this.CP = in.readInt();
    this.activo = in.readInt();
    this.done = in.readInt();
    this.sincronizado = in.readInt();
    this.idRuta = in.readInt();

    this.latitude = in.readDouble();
    this.longitude = in.readDouble();

    this.telefono = in.readString();
    this.contacto = in.readString();
    this.horarioIni = in.readString();
    this.horarioFin = in.readString();
    this.proyecto = in.readParcelable(Proyecto.class.getClassLoader());

    }
// getters and setters ...
}

这是我的proguard.project.txt

    ##---------------Begin: proguard configuration common for all Android apps ----------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt 
-printseeds seeds.txt 
-printusage unused.txt 
-printmapping mapping.txt 
-optimizations !code/simplification/arithmetic


-injars      bin/classes
-injars      libs
-outjars     bin/classes-processed.jar



-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''


-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

-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-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();
}


# Preserve all native method names and the names of their classes.
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclassmembers class * extends android.content.Context {
   public void *(android.view.View);
   public void *(android.view.MenuItem);
}
-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}


-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}


-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}


# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
  public static <fields>;
}


# Preserve the special static methods that are required in all enumeration classes.
-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 *;
}
##---------------End: proguard configuration common for all Android apps ----------


##---------------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


# 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 com.google.gson.examples.android.model.** { *; }


##---------------End: proguard configuration for Gson  ----------

##---------------Begin proguard configuration for Google Maps --------------------

-keep class com.google.android.gms.** { *; }
-dontwarn com.google.android.gms.**

-keep class org.** { *; }
-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 * {
    @com.google.android.gms.common.annotation.KeepName *;
}


-renamesourcefileattribute SourceFile    
-keepattributes SourceFile,LineNumberTable

##---------------End proguard configuration for Google Maps --------------------

##---------------Begin proguard configuration for my libs  -----------------------
-keep class com.todddavies.components.progressbar.** { *; }
-dontwarn com.todddavies.components.progressbar.**

-dontwarn org.apache.**


-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
}

我已经看过几篇帖子,但都没有解决我的问题

Proguard causing RuntimeException (Unmarshalling unknown type code) in Parcelable class

我可以将parcelable更改为json字符串,但我有其他parcelables对象,并且我害怕将来有其他类似的问题。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

当Android尝试从通过IPC传递的Bundle中读取任何值(通过startActivity,sendBroadcast等发送)时,它将取消打包整个Bundle中的所有内容。如果Android遇到类路径中未包含的任何类,则会抛出java.lang.ClassNotFoundException

有些尝试,您可能需要其中一项或多项:

在您的proguard.pro文件中包括以下内容,以保留用于CREATOR的Parcelables,这是通过Android反射来引用的(我认为Google会自动将此规则添加到每个应用程序中,但有时它并不取决于您的应用构建系统):​​

# keep CREATOR for referenced parcelables since it is accessed via reflection
-keepclassmembers class * implements android.os.Parcelable {
    static ** CREATOR;
}

在从捆绑包中取出任何东西之前,请添加类加载器。假设此代码是从您APK中的一个类运行的(因此与额外的自定义Parcelable类共享相同的类加载器),或者您可以传递Context并使用Context#getClassLoader()处于静态方法中:

extras.setClassLoader(getClass().getClassLoader());

如果捆绑包中确实没有使用但您在类路径中的Parcelable,则使用此规则保留所有Parcelable:

# Keep all known parcelables
-keep public class * implements android.os.Parcelable

最后,如果您为某个应用程序在构建时不知道的类传递了一个Bundle和一个Parcelable,那么Bundle可能会中毒,您将无法完全使用它。这是使您不喜欢的其他Android应用程序崩溃的好方法!最好的办法是尝试捕获首次访问该捆绑包的代码块,以免使应用程序崩溃。

try {
  Bundle extras = getIntent().getExtras();
  if (extras != null) {
    // Trigger unparcel
    extras.size();
  }
} catch (BadParcelableException e) {
  Log.w(TAG, "Got poison Bundle or programmer needs to fix proguard/classloader", e);
}