Class 在 Proguard 启用时解组时未找到
Class not found when unmarshalling when Proguard enabled
我一直在处理似乎是 Proguard 配置问题。我的应用程序在调试时工作正常,但发布的 apk 在启动 2nd activity 时给我一个异常。这似乎是在尝试从 Intent 中检索 Parcelable extras 时发生的。
这是堆栈跟踪:
E/Parcel﹕ Class not found when unmarshalling: com.mycompany.model.Task
java.lang.ClassNotFoundException: com.mycompany.model.Task
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.lang.Class.forName(Class.java:216)
at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
at android.os.Parcel.readParcelable(Parcel.java:2097)
at android.os.Parcel.readValue(Parcel.java:2013)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
at android.os.Bundle.unparcel(Bundle.java:249)
at android.os.Bundle.getString(Bundle.java:1118)
at android.content.Intent.getStringExtra(Intent.java:5128)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1447)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1043)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4054)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3948)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2629)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.NoClassDefFoundError: com/mycompany/model/Task
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.lang.Class.forName(Class.java:216)
at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
at android.os.Parcel.readParcelable(Parcel.java:2097)
at android.os.Parcel.readValue(Parcel.java:2013)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
at android.os.Bundle.unparcel(Bundle.java:249)
at android.os.Bundle.getString(Bundle.java:1118)
at android.content.Intent.getStringExtra(Intent.java:5128)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1447)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1043)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4054)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3948)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2629)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.mycompany.model.Task" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67)
at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.lang.Class.forName(Class.java:216)
at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
at android.os.Parcel.readParcelable(Parcel.java:2097)
at android.os.Parcel.readValue(Parcel.java:2013)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
at android.os.Bundle.unparcel(Bundle.java:249)
at android.os.Bundle.getString(Bundle.java:1118)
at android.content.Intent.getStringExtra(Intent.java:5128)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1447)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1043)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4054)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3948)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2629)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
有 Parcelable Task 模型:
public class Task implements Parcelable {
public enum Mode {MODE1, MODE2}
public enum Type {TYPE1, TYPE2, TYPE3}
private final String id;
private final Mode mode;
private final Type type;
private ArrayList<Character> charactersList;
public Task(String id, ArrayList<Character> characters, Mode mode, Type type) {
this.id = id;
this.charactersList = characters;
this.mode = mode;
this.type = type;
}
public Mode getMode() {
return mode;
}
public Type getType() {
return type;
}
public String getId() {
return id;
}
public ArrayList<Character> getCharactersList() {
return charactersList;
}
private Task(Parcel in) {
id = in.readString();
Parcelable[] parcelablecharactersArray = in.readParcelableArray(Character.class.getClassLoader());
charactersList = new ArrayList<>();
for (Parcelable p : parcelablecharactersArray) {
charactersList.add((Character) p);
}
mode = Mode.valueOf(in.readString());
type = Type.valueOf(in.readString());
}
public static final Parcelable.Creator<Task> CREATOR = new Parcelable.Creator<Task>() {
public Task createFromParcel(Parcel in) {
return new Task(in);
}
public Task[] newArray(int size) {
return new Task[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeParcelableArray(charactersList.toArray(new Parcelable[charactersList.size()]), 0);
dest.writeString(mode.name());
dest.writeString(type.name());
}
}
还有 activity 启动和接收意图:
public class TaskActivity {
private Task mTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(null);
Bundle extras = getIntent().getExtras();
mTask = extras.getParcelable(Constants.TASK_KEY);
}
private void launchNextTask(Task nextTask) {
if (nextTask != null) {
Intent intent = new Intent(TaskActivity.this, TaskActivity.class);
intent.putExtra(Constants.TASK_KEY, nextTask);
startActivity(intent);
}
}
}
混淆器规则:
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keep public class com.mycompany.model.Task { *; }
-keep public class com.mycompany.model.Character { *; }
-keep public class com.mycompany.Constants { *; }
您知道问题出在哪里吗?我的第一个猜测是尝试在 Parcelable 构造函数中创建 Character ArrayList 时类加载器有问题(顺便说一下,Character 也实现了 Parcelable)。第二个猜测是枚举。
我认为问题出在 Parcelable
Task
extends.
# could be refined, but if it works you got the idea
-keepnames class * implements android.os.Parcelable { *; }
-keepclassmembers class * implements android.os.Parcelable { *; }
-keep public class com.mycompany.model.Task { *; }
找到答案了。它是 Proguard 配置。但这不是关于 Parcelable 或 Task,而是关于另一个模块中的其他 类 被混淆了,不应该被混淆。
正在添加
-keep public class com.othermodule.OtherClass { *; }
成功了。
所以堆栈跟踪有点误导,或者至少不够明确。
无论如何,谢谢@shkschneider 的帮助。
我一直在处理似乎是 Proguard 配置问题。我的应用程序在调试时工作正常,但发布的 apk 在启动 2nd activity 时给我一个异常。这似乎是在尝试从 Intent 中检索 Parcelable extras 时发生的。
这是堆栈跟踪:
E/Parcel﹕ Class not found when unmarshalling: com.mycompany.model.Task
java.lang.ClassNotFoundException: com.mycompany.model.Task
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.lang.Class.forName(Class.java:216)
at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
at android.os.Parcel.readParcelable(Parcel.java:2097)
at android.os.Parcel.readValue(Parcel.java:2013)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
at android.os.Bundle.unparcel(Bundle.java:249)
at android.os.Bundle.getString(Bundle.java:1118)
at android.content.Intent.getStringExtra(Intent.java:5128)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1447)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1043)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4054)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3948)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2629)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.NoClassDefFoundError: com/mycompany/model/Task
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.lang.Class.forName(Class.java:216)
at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
at android.os.Parcel.readParcelable(Parcel.java:2097)
at android.os.Parcel.readValue(Parcel.java:2013)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
at android.os.Bundle.unparcel(Bundle.java:249)
at android.os.Bundle.getString(Bundle.java:1118)
at android.content.Intent.getStringExtra(Intent.java:5128)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1447)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1043)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4054)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3948)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2629)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.mycompany.model.Task" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67)
at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.lang.Class.forName(Class.java:216)
at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
at android.os.Parcel.readParcelable(Parcel.java:2097)
at android.os.Parcel.readValue(Parcel.java:2013)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
at android.os.Bundle.unparcel(Bundle.java:249)
at android.os.Bundle.getString(Bundle.java:1118)
at android.content.Intent.getStringExtra(Intent.java:5128)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1447)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1043)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4054)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3948)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2629)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
有 Parcelable Task 模型:
public class Task implements Parcelable {
public enum Mode {MODE1, MODE2}
public enum Type {TYPE1, TYPE2, TYPE3}
private final String id;
private final Mode mode;
private final Type type;
private ArrayList<Character> charactersList;
public Task(String id, ArrayList<Character> characters, Mode mode, Type type) {
this.id = id;
this.charactersList = characters;
this.mode = mode;
this.type = type;
}
public Mode getMode() {
return mode;
}
public Type getType() {
return type;
}
public String getId() {
return id;
}
public ArrayList<Character> getCharactersList() {
return charactersList;
}
private Task(Parcel in) {
id = in.readString();
Parcelable[] parcelablecharactersArray = in.readParcelableArray(Character.class.getClassLoader());
charactersList = new ArrayList<>();
for (Parcelable p : parcelablecharactersArray) {
charactersList.add((Character) p);
}
mode = Mode.valueOf(in.readString());
type = Type.valueOf(in.readString());
}
public static final Parcelable.Creator<Task> CREATOR = new Parcelable.Creator<Task>() {
public Task createFromParcel(Parcel in) {
return new Task(in);
}
public Task[] newArray(int size) {
return new Task[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeParcelableArray(charactersList.toArray(new Parcelable[charactersList.size()]), 0);
dest.writeString(mode.name());
dest.writeString(type.name());
}
}
还有 activity 启动和接收意图:
public class TaskActivity {
private Task mTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(null);
Bundle extras = getIntent().getExtras();
mTask = extras.getParcelable(Constants.TASK_KEY);
}
private void launchNextTask(Task nextTask) {
if (nextTask != null) {
Intent intent = new Intent(TaskActivity.this, TaskActivity.class);
intent.putExtra(Constants.TASK_KEY, nextTask);
startActivity(intent);
}
}
}
混淆器规则:
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keep public class com.mycompany.model.Task { *; }
-keep public class com.mycompany.model.Character { *; }
-keep public class com.mycompany.Constants { *; }
您知道问题出在哪里吗?我的第一个猜测是尝试在 Parcelable 构造函数中创建 Character ArrayList 时类加载器有问题(顺便说一下,Character 也实现了 Parcelable)。第二个猜测是枚举。
我认为问题出在 Parcelable
Task
extends.
# could be refined, but if it works you got the idea
-keepnames class * implements android.os.Parcelable { *; }
-keepclassmembers class * implements android.os.Parcelable { *; }
-keep public class com.mycompany.model.Task { *; }
找到答案了。它是 Proguard 配置。但这不是关于 Parcelable 或 Task,而是关于另一个模块中的其他 类 被混淆了,不应该被混淆。
正在添加
-keep public class com.othermodule.OtherClass { *; }
成功了。
所以堆栈跟踪有点误导,或者至少不够明确。
无论如何,谢谢@shkschneider 的帮助。