Android ProGuard +MultiDex 导致 ClassNotFoundException

Posted

技术标签:

【中文标题】Android ProGuard +MultiDex 导致 ClassNotFoundException【英文标题】:Android ProGuard +MultiDex causes ClassNotFoundException 【发布时间】:2015-04-19 02:29:36 【问题描述】:

我在我的 android 项目中启用了MultiDex。在我尝试启用 proguard 之前它工作正常。我可以成功构建项目,但在启动时出现运行时异常。它无法找到 Application 类和 MainActivity。在启用MultiDex 之前我遇到了同样的问题。现在我猜出于某种原因MultiDex 不能与ProGuard 一起正常工作。这是我在 logcat 中得到的 -

02-17 19:01:09.749: I/MultiDex(2079): VM with version 2.1.0 has multidex support
02-17 19:01:09.749: I/MultiDex(2079): install
02-17 19:01:09.749: I/MultiDex(2079): VM has multidex support, MultiDex support library is disabled.
02-17 19:01:09.750: I/art(2079): Rejecting re-init on previously-failed class java.lang.Class<android.support.v4.app.FragmentActivity>
02-17 19:01:09.750: I/art(2079): Rejecting re-init on previously-failed class java.lang.Class<android.support.v4.app.FragmentActivity>
02-17 19:01:09.751: I/art(2079): Rejecting re-init on previously-failed class java.lang.Class<mypackage.activities.MainActivity>
02-17 19:01:09.751: I/art(2079): Rejecting re-init on previously-failed class java.lang.Class<mypackage.activities.MainActivity>
02-17 19:01:09.751: D/AndroidRuntime(2079): Shutting down VM
02-17 19:01:09.751: D/AndroidRuntime(2079): --------- beginning of crash 

然后堆栈跟踪的其余部分是关于 MainActivity 的 ClassNotFoundException:

02-17 19:01:09.752: E/AndroidRuntime(2079): FATAL EXCEPTION: main
02-17 19:01:09.752: E/AndroidRuntime(2079): Process: com.mypackage, PID: 2079
02-17 19:01:09.752: E/AndroidRuntime(2079): java.lang.NoClassDefFoundError: Failed resolution of: Lcom/mypackage/activities/MainActivity;
02-17 19:01:09.752: E/AndroidRuntime(2079):     at cmypackage.application.ApplicationContextProvider.onCreate(Unknown Source)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4518)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.app.ActivityThread.access$1500(ActivityThread.java:144)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1339)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.os.Handler.dispatchMessage(Handler.java:102)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.os.Looper.loop(Looper.java:135)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at android.app.ActivityThread.main(ActivityThread.java:5221)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at java.lang.reflect.Method.invoke(Native Method)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at java.lang.reflect.Method.invoke(Method.java:372)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
02-17 19:01:09.752: E/AndroidRuntime(2079): Caused by: java.lang.ClassNotFoundException: Didn't find class "mypackage.activities.MainActivity" on path: DexPathList[[zip file "/data/app/mypackage-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
02-17 19:01:09.752: E/AndroidRuntime(2079):     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
02-17 19:01:09.752: E/AndroidRuntime(2079):     at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
02-17 19:01:09.752: E/AndroidRuntime(2079):     ... 12 more
02-17 19:01:09.752: E/AndroidRuntime(2079):     Suppressed: java.lang.NoClassDefFoundError: mypackage.activities.MainActivity
02-17 19:01:09.752: E/AndroidRuntime(2079):         at dalvik.system.DexFile.defineClassNative(Native Method)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at dalvik.system.DexFile.defineClass(DexFile.java:226)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:219)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at dalvik.system.DexPathList.findClass(DexPathList.java:321)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
02-17 19:01:09.752: E/AndroidRuntime(2079):         ... 14 more
02-17 19:01:09.752: E/AndroidRuntime(2079):     Suppressed: java.lang.ClassNotFoundException: mypackage.MainActivity
02-17 19:01:09.752: E/AndroidRuntime(2079):         at java.lang.Class.classForName(Native Method)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
02-17 19:01:09.752: E/AndroidRuntime(2079):         at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
02-17 19:01:09.752: E/AndroidRuntime(2079):         ... 13 more
02-17 19:01:09.752: E/AndroidRuntime(2079):     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

编辑- 这是我的 proguard 规则文件:

-libraryjars libs

# We only want obfuscation
-keepattributes InnerClasses,Signature

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-dontoptimize
-verbose

# Sdk
-keep public interface com.zendesk.sdk.**  *; 
-keep public class com.zendesk.sdk.**  *; 

# Appcompat and support
#-keep interface android.support.v7.**  *; 
#-keep class android.support.v7.**  *; 
#-keep interface android.support.v4.**  *; 
#-keep class android.support.v4.**  *; 

# Gson
-keep interface com.google.gson.**  *; 
-keep class com.google.gson.**  *; 

# Retrofit
#-keep class com.google.inject.**  *; 
#-keep class org.apache.http.**  *; 
#-keep class org.apache.james.mime4j.**  *; 
#-keep class javax.inject.**  *; 
#-keep class retrofit.**  *; 
#-keep interface retrofit.**  *; 

# Retrofit
-keep class com.squareup.okhttp.**  *; 
-keep interface com.squareup.okhttp.**  *; 
-dontwarn com.squareup.okhttp.**

-dontwarn rx.**
-dontwarn retrofit.**
-dontwarn okio.**
-keep class retrofit.**  *; 
-keepclasseswithmembers class * 
    @retrofit.http.* <methods>;


# Jackson
-keepattributes *Annotation*,EnclosingMethod,Signature
-keepnames class com.fasterxml.jackson.**  *; 
 -dontwarn com.fasterxml.jackson.databind.**
 -keep class org.codehaus.**  *; 
 -keepclassmembers public final enum org.codehaus.jackson.annotate.JsonAutoDetect$Visibility 
 public static final org.codehaus.jackson.annotate.JsonAutoDetect$Visibility *; 
-keep public class mypackage.parsers.JacksonParser.** 
  public void set*(***);
  public *** get*();


#Picasso
-dontwarn com.squareup.okhttp.**

#-dontwarn javax.management.**
#-dontwarn java.lang.management.**
#-dontwarn org.apache.log4j.**
#-dontwarn org.apache.commons.logging.**
#-dontwarn org.json.*
#-dontwarn org.apache.commons.codec.binary.Base64

#-keep class javax.** * ; 
#-keep class org.**  *; 

-dontwarn org.mortbay.**
-dontwarn org.slf4j.**
-dontwarn org.apache.log4j.**
-dontwarn org.apache.commons.logging.**
-dontwarn org.apache.commons.codec.binary.**

【问题讨论】:

你解决过这个问题吗? 我遇到了类似的问题 【参考方案1】:

This page 说:

默认的proguard.cfg 文件试图涵盖一般情况,但您 可能会遇到ClassNotFoundException 等异常,其中 当 ProGuard 剥离你的整个类时会发生 应用程序调用。

当 ProGuard 剥离您的代码时,您可以通过添加 proguard.cfg 文件中的 -keep 行。例如:

-keep public class <MyClass>

使用 -keep 选项时有许多选项和注意事项, 因此强烈建议您阅读 ProGuard 手册以了解更多信息 有关自定义配置文件的信息。概述 保留选项和示例部分特别有用。这 ProGuard 手册的故障排除部分概述了其他常见的 当你的代码被剥离时你可能会遇到的问题。

解决方案 1

您可以尝试以下 proguard.cfg 我曾经在不优化时混淆代码,因此不会从您的 APK 中删除类/方法。

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-dontoptimize
-verbose

解决方案 2

您要求保留一些课程,但不是为MainActivity。所以你必须添加这一行:

-keep class com.mypackage.activities.MainActivity  *; 

【讨论】:

感谢您的回复。我会尝试您建议的规则,但我实际上是在尝试优化代码。由于 MultiDex 在一些棒棒糖之前的设备上导致运行时异常。所以,我正在尝试使用 proguard 来优化代码,并且可能会减少内存使用量。 bw 我正在将所有规则添加到 proguard-rules.pro 文件中。 并添加这些规则没有帮助。我仍然遇到同样的异常 “并添加这些规则没有帮助。我仍然遇到同样的异常”,我认为你没有评论 proguard 以前的命令,这就是它没有帮助的原因。跨度> 之前的命令是什么?我在 proguard 文件中有很多规则。你可以看看。 我应该在我的问题中提到;我已经尝试为 MainActivity 甚至整个项目添加异常,但仍然是同样的问题。我想这与 MultiDex 有关,正如您在堆栈跟踪中看到的那样

以上是关于Android ProGuard +MultiDex 导致 ClassNotFoundException的主要内容,如果未能解决你的问题,请参考以下文章

bugly使用问题记录