简体   繁体   English

MultiDex NoClassDefFound 错误

[英]MultiDex NoClassDefFound error

I have converted my application into MultiDex to bear with 64k dex limit.我已将我的应用程序转换为 MultiDex 以承受 64k dex 的限制。 Now it looks like this:现在它看起来像这样:

public class App extends MultiDexApplication {

private AppWrapper instance;

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(base);
}

@Override
public void onCreate() {
    super.onCreate();

    if (instance == null) {
        instance = new AppWrapper(this);
    }
}
}

I've pulled all the usual logic from App to AppWidget to make MultiDex work.我已经将所有常用的逻辑从 App 拉到AppWidget以使MultiDex工作。 And it works ok on other teammates' computers.它在其他队友的电脑上运行正常。 But not with me.但不是和我在一起。 It keeps throwing java.lang.NoClassDefFoundError on application create:它在应用程序创建时不断抛出java.lang.NoClassDefFoundError

I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed
I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed
E/dalvikvm﹕ Could not find class     'com.playday.app.core.AppWrapper', referenced from method com.playday.app.core.App.onCreate
W/dalvikvm﹕ VFY: unable to resolve     new-instance 7076 (Lcom/playday/app/core/AppWrapper;) in Lcom/playday/app/core/App;
D/dalvikvm﹕ VFY: replacing opcode     0x22 at 0x0007
I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed
D/dalvikvm﹕ DexOpt: unable to opt     direct call 0xc21b at 0x09 in Lcom/playday/app/core/App;.onCreate
I/MultiDex﹕ VM with version 1.6.0     does not have multidex support
I/MultiDex﹕ install
I/MultiDex﹕ MultiDexExtractor.load(    /data/app/com.playdayteam.playday.debug-1.apk, false)
I/MultiDex﹕ Detected that     extraction must be performed.
I/MultiDex﹕ Trying to delete old     file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.    debug-2.apk.classes2.dex of size 1484912
I/MultiDex﹕ Deleted old file     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-2    .apk.classes2.dex
I/MultiDex﹕ Trying to delete old     file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.    debug-2.apk.classes2.zip of size 540964
I/MultiDex﹕ Deleted old file     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-2    .apk.classes2.zip
D/dalvikvm﹕ GC_CONCURRENT freed     186K, 11% free 3245K/3640K, paused 2ms+4ms, total 28ms
D/dalvikvm﹕ WAIT_FOR_CONCURRENT_GC     blocked 5ms
D/dalvikvm﹕ GC_CONCURRENT freed     156K, 8% free 3593K/3904K, paused 3ms+2ms, total 22ms
I/MultiDex﹕ Extraction is needed     for file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.    playday.debug-1.apk.classes2.zip
I/MultiDex﹕ Extracting     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1    .apk.classes576886388.zip
I/MultiDex﹕ Renaming to     /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1    .apk.classes2.zip
I/MultiDex﹕ Extraction success -     length /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.    debug-1.apk.classes2.zip: 540964
I/MultiDex﹕ load found 1 secondary     dex files
D/dalvikvm﹕ DexOpt: --- BEGIN 'com.    playdayteam.playday.debug-1.apk.classes2.zip' (bootstrap=0) ---
D/dalvikvm﹕ DexOpt: --- END 'com.    playdayteam.playday.debug-1.apk.classes2.zip' (success) ---
D/dalvikvm﹕ DEX prep '/data/data/com    .playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1.apk.classes2.    zip': unzip in 28ms, rewrite 387ms
I/MultiDex﹕ install done
I/MultiDex﹕ install
D/AndroidRuntime﹕ Shutting down VM
W/dalvikvm﹕ threadid=1: thread     exiting with uncaught exception (group=0x41c1d930)
E/AndroidRuntime﹕ FATAL EXCEPTION:     main
    java.lang.NoClassDefFoundError: com.playday.app.core.AppWrapper
            at com.playday.app.core.App.onCreate(App.java:22)
            at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1006)
            at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4457)
            at android.app.ActivityThread.access$1300(ActivityThread.java:142)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1332)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5105)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)    

I have the same Android Studio, gradle, sdk, jdk versions, same code.我有相同的 Android Studio、gradle、sdk、jdk 版本,相同的代码。 I've even tried to format hard drive and reinstall OS to make sure that environment is the same.我什至尝试过格式化硬盘并重新安装操作系统以确保环境相同。 What can be the cause of this strange problem?这个奇怪问题的原因是什么?

This is my build.gradle :这是我的build.gradle

apply plugin: 'com.android.application'

repositories {
    maven { url 'http://dl.bintray.com/populov/maven' }
    mavenCentral()
    maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}

android {
    compileSdkVersion project.api_level
    buildToolsVersion project.build_tools_version

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion project.api_level
    }

    sourceSets {
        instrumentTest.setRoot('src/test')
    }

    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/ASL2.0'
        exclude 'AndroidManifest.xml'
    }

    defaultConfig {
        versionName "0.3.2"
        versionCode 23
    }

    buildTypes {

        debug {
            debuggable true
            applicationIdSuffix ".debug"
        }

        beta {
            debuggable true
            signingConfig signingConfigs.release
            applicationIdSuffix ".beta"
        }

        release {
            signingConfig signingConfigs.release
            runProguard false
            proguardFile file('proguard-rules.txt')
            proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
        }
    }

    dexOptions {
        incremental false
        preDexLibraries false
    }
}

dependencies {
    compile "com.android.support:support-v13:$project.support_lib_version"
    compile "com.android.support:support-v4:$project.support_lib_version"
    compile "com.android.support:appcompat-v7:$project.support_lib_version"
    compile 'com.google.android.gms:play-services:6.1.11'
    compile('de.keyboardsurfer.android.widget:crouton:1.8.5@aar') {
        exclude group: 'com.google.android', module: 'support-v4'
    }
    compile('com.octo.android.robospice:robospice:1.4.14'){
        exclude group: 'commons-io', module: 'commons-io'
    }
    compile('com.octo.android.robospice:robospice-retrofit:1.4.14'){
        exclude group: 'commons-io', module: 'commons-io'
    }
    compile 'com.squareup.retrofit:retrofit:1.6.1'
    compile 'com.google.code.gson:gson:2.3'
    compile 'com.viewpagerindicator:library:2.4.1@aar'
    compile 'com.squareup.picasso:picasso:2.3.3'
    compile 'com.squareup.okhttp:okhttp:2.0.0'
    compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'

    compile 'com.etsy.android.grid:library:1.0.5'
    compile 'com.squareup:otto:1.3.4'
    compile 'com.darwinsys:hirondelle-date4j:1.5.1'
    compile 'com.github.chrisbanes.photoview:library:1.2.3'
    compile 'me.grantland:autofittextview:0.2.0'
    compile 'it.sephiroth.android.library.horizontallistview:library:1.2.1'
    compile 'org.ocpsoft.prettytime:prettytime:3.2.4.Final'
    compile 'com.google.guava:guava:18.0'
    compile 'com.github.castorflex.smoothprogressbar:library:0.5.2'
    compile 'com.makeramen:roundedimageview:1.3.0'
    compile 'org.lucasr.twowayview:twowayview:0.1.1'
    compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'

    compile project(':libs:LoopingViewPager')
    compile project(':libs:PhotoView-2.2.1')
    compile files('libs/localytics.jar')
    compile files('libs/android-support-multidex.jar')

    compile 'net.hockeyapp.android:HockeySDK:3.0.2'
}

afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = []
        }
        dx.additionalParameters += '--multi-dex' // enable multidex
        dx.additionalParameters += "--main-dex-list=$projectDir/multidex.keep".toString()
    }
}

Update.更新。 My multidex.keep file:我的multidex.keep文件:

android/support/multidex/BuildConfig.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/MultiDex$V4.class
android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/ZipUtil$CentralDirectory.class
android/support/multidex/ZipUtil.class
com/playday/app/models/notification/Badge.class
com/playday/app/models/User.class
com/playday/app/core/AppWrapper.class
com/playday/app/core/App.class

Your AppWrapper class fails to load because the retrofit.ErrorHandler interface is not included in main dex file.因为retrofit.ErrorHandler接口不是主要DEX文件中包含你的AppWrapper类加载失败。

How do you calculate which classes to put in your main-dex-list file?您如何计算将哪些类放入 main-dex-list 文件中?
There's a script that can generate it for you.有一个脚本可以为您生成它。 I wrote a blogpost that shows how to use it.我写了一篇博文,展示了如何使用它。

Update (10/31/2014) :更新(10/31/2014)
Gradle plugin v0.14.0 now does it automatically. Gradle 插件 v0.14.0 现在会自动执行。 See my answer here .在这里看到我的答案。

Update (24/04/2017) :更新(24/04/2017)
The developer guide explains how to pick specific classes with a gradle option if it doesn't pick all the right ones automatically.如果没有自动选择所有正确的类, 开发人员指南解释了如何使用 gradle 选项选择特定类。

if everything looks OK, but this error appears,如果一切正常,但出现此错误,

try to disable instant run!!!尝试禁用即时运行!!!

when I disabled it all the classes were loaded properly.当我禁用它时,所有类都被正确加载。

If you're extending the MultiDexApplication you don't need to make the MultiDex.install(context) call as it's already happening (see source link).如果您正在扩展 MultiDexApplication,则不需要进行 MultiDex.install(context) 调用,因为它已经发生了(请参阅源链接)。 If you need to use attachBaseContext then just make sure to call super.attachBaseContext(context).如果您需要使用 attachBaseContext 那么只需确保调用 super.attachBaseContext(context)。

https://android.googlesource.com/platform/frameworks/multidex/+/1bb1ab007f6b9405227ea4ce07d2061e4dbb6fe0/library/src/android/support/multidex/MultiDexApplication.java https://android.googlesource.com/platform/frameworks/multidex/+/1bb1ab007f6b9405227ea4ce07d2061e4dbb6fe0/library/src/android/support/multidex/MultiDexApplication.java

We just updated developers.android.com with instructions on how to use the support library with the Android gradle plugin including an development optimization for quick development build cycle times.我们刚刚更新了 developer.android.com,其中包含有关如何将支持库与 Android gradle 插件配合使用的说明,包括针对快速开发构建周期的开发优化。

https://developer.android.com/tools/building/multidex.html https://developer.android.com/tools/building/multidex.html

If anyone gets here because their Application class is not being found on pre-Lollipop devices, but the app runs fine on Lollipop and above then this appears to be a known issue with Jack and Multidex.如果有人因为在 Lollipop 之前的设备上找不到他们的 Application 类而来到这里,但该应用程序在 Lollipop 及更高版本上运行良好,那么这似乎是 Jack 和 Multidex 的一个已知问题。

Ref: Jack Issue 213484参考:杰克问题 213484

Ref: Jack Issue 224026参考:杰克问题 224026

The NoClassDefFound can happen with any arbitrary class that did not load up on a device with API earlier than Lollipop and with multidex enabled. NoClassDefFound可能发生在任何未在具有早于 Lollipop 的 API 且启用了 multidex 的设备上加载的任意类。 If you set up ProGuard properly then you can easily get by without having the MultiDex overhead making your app slow to launch for your release builds, especially on old devices.如果您正确设置了 ProGuard,那么您就可以轻松度过难关,而不会因为 MultiDex 开销而使您的应用程序在发布版本时启动缓慢,尤其是在旧设备上。 However, you don't want ProGuard slowing you down while you develop your app in debug mode.但是,当您在调试模式下开发应用程序时,您不希望 ProGuard 减慢您的速度。 If you try to launch your debug build with ProGuard disabled, you will start to get build errors like com.android.dex.DexIndexOverflowException: Cannot merge new index 72118 into a non-jumbo instruction!如果您尝试在禁用 ProGuard 的情况下启动调试构建,您将开始收到构建错误,例如com.android.dex.DexIndexOverflowException: Cannot merge new index 72118 into a non-jumbo instruction!

So what you really want is ProGuard enabled and multidex disabled only on release builds, while debug builds should be the opposite with Proguard disabled and multidex enabled.因此,您真正想要的是仅在发布版本中启用 ProGuard 和禁用 multidex,而调试版本应该与禁用 Proguard 和启用 multidex 的情况相反。 You also have to be picky and use less dependencies, of course, because your release build will be subject to the 64K limit.当然,您还必须挑剔并使用较少的依赖项,因为您的发布版本受到 64K 的限制。

This requires setting up build.gradle to have buildTypes configs, and compiling the multidex support library dependency only for debug.这需要将 build.gradle 设置为具有buildTypes配置,并编译 multidex 支持库依赖项仅用于调试。

The Application subclass must also be set to derive from a different subclass depending on whether you're in multidex mode or not. Application 子类还必须设置为派生自不同的子类,具体取决于您是否处于多索引模式。 This can be achieved using the gradle manifest merger principle, by defining an override manifest for your debug build, and then specifying your Application class differently.这可以使用 gradle 清单合并原则来实现,方法是为您的调试版本定义一个覆盖清单,然后以不同的方式指定您的应用程序类。

Here's the relevant app module build.gradle:这是相关的应用模块 build.gradle:

android {
...
    buildTypes {
        debug {
            minifyEnabled false //Disabled Proguard
            multiDexEnabled true // Enabling multi-dex support.
        }
        release {
            minifyEnabled true //Enabled Proguard
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            multiDexEnabled false // Disable multi-dex support.
        }
    }
    dependencies {
        debugCompile 'com.android.support:multidex:1.0.1' //debugCompile makes it included only for debug builds
        ...
    }
}

If you don't use an Application subclass, then all you need to do is specify the name of the Application subclass android.support.multidex.MultiDexApplication as noted in https://developer.android.com/studio/build/multidex.html but you want to do this only for your debug build.如果您不使用应用程序子类,那么您需要做的就是指定应用程序子类android.support.multidex.MultiDexApplication的名称,如https://developer.android.com/studio/build/multidex 中所述。 HTML但你想为您的调试版本做到这一点。

For this, you have to specify overriding files in the debug and release variant folder hierarchy, like so:为此,您必须在调试和发布变体文件夹层次结构中指定覆盖文件,如下所示:

src
    - main
        - AndroidManifest.xml
        - java/com/yourcompany/MyApplication.java (extends from BaseApplication)
    - release
        - java/com/yourcompany/BaseApplication.java (extends from Application)
    - debug
        - AndroidManifest.xml
        - java/com/yourcompany/BaseApplication.java (extends from MultiDexApplication)

Yes, you create debug and release folders next to your main module's folder.是的,您在主模块的文件夹旁边创建debugrelease文件夹。 Add the following files within:在其中添加以下文件:

debug/AndroidManifest.xml调试/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >
    <application
        android:name="com.yourcompany.MyApplication"
        tools:replace="android:name"/>
</manifest>

This manifest will only be included in debug builds, and will be ignored for your release one.此清单将仅包含在调试版本中,并且在您的第一个版本中将被忽略。

release/java/com/yourcompany/BaseApplication.java发布/java/com/yourcompany/BaseApplication.java

public class BaseApplication extends Application {
}

debug/java/com/yourcompany/BaseApplication.java调试/java/com/yourcompany/BaseApplication.java

public class BaseApplication extends MultiDexApplication {
}            

main/java/com/yourcompany/MyApplication.java main/java/com/yourcompany/MyApplication.java

public class MyApplication extends BaseApplication {
    @Override
    public void onCreate() {
        super.onCreate();
        //Init database, etc. etc.;
    }
}            

In this way, you can add your App's functionality into MyApplication.java while having differing base classes.通过这种方式,您可以将应用程序的功能添加到MyApplication.java同时拥有不同的基类。

I also got this kind of problem.我也遇到了这样的问题。 Solution in my case was: In my build.gradle file, there were multiple entries of compile 'com.android.support:multidex:1.0.0' in dependencies.我的解决方案是:在我的 build.gradle 文件中,依赖项中有多个compile 'com.android.support:multidex:1.0.0'条目。 like:喜欢:

dependencies {    
compile 'com.android.support:multidex:1.0.0'
compile 'com.android.support:multidex:1.0.0'
// other dependencies ........
}

just put only one compile 'com.android.support:multidex:1.0.0' like:只放一个编译 'com.android.support:multidex:1.0.0' 像:

dependencies {    
compile 'com.android.support:multidex:1.0.0'
// other dependencies ........
}

I've finally solved it!我终于解决了! Cause was not in the onCreate() method.原因不在onCreate()方法中。 There was this line from logcat that gained my attention: logcat 的这一行引起了我的注意:

I/dalvikvm﹕ Failed resolving     Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class     'Lcom/playday/app/core/AppWrapper;' failed

This line fired before all the MultiDex log.此行在所有 MultiDex 日志之前触发。 Source of the problem was Retrofit ErrorHandler interface, which AppWrapper implements.问题的AppWrapper实现的 Retrofit ErrorHandler接口。

As @AlexLipov said in his answer, Dalvik just couldn't find ErrorHandler class and failed to load AppWrapper .正如@AlexLipov 在他的回答中所说,Dalvik 只是找不到ErrorHandler类并且无法加载AppWrapper

Anyway, solution is not to implement ErrorHandler directly by AppWrapper and pull it into private variable instead.无论如何,解决方案不是通过AppWrapper直接实现ErrorHandler AppWrapper将其拉入私有变量。

I tried with a lot of solutions a no one worked for me.我尝试了很多解决方案,但没有人为我工作。 Finally, I found this:最后,我发现了这个:

    public class MyApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

And was the only solution for my problem.并且是我问题的唯一解决方案。 Maybe someone is having the same problem and this could help :)也许有人遇到了同样的问题,这可能会有所帮助:)

Add below dependency in gradle在gradle中添加以下依赖项

implementation 'com.android.support:multidex:1.0.3'

In app level build.gradle,add parameters like below.在应用级 build.gradle 中,添加如下参数。

 defaultConfig {
     multiDexEnabled = true
 }

In Application class,add below line在 Application 类中,添加以下行

MultiDex.install(this);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM