Ошибка MultiDex NoClassDefFound

Я конвертировал свое приложение в MultiDex, чтобы иметь ограничение 64k dex. Теперь это выглядит так:

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);
    }
}
}

Я вытащил всю обычную логику из приложения в AppWidget, чтобы сделать работу MultiDex. И он работает нормально на компьютерах других товарищей по команде. Но не со мной. Он продолжает метать 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)    

У меня есть те же версии Android Studio, gradle, sdk, jdk, тот же код. Я даже пытался отформатировать жесткий диск и переустановить ОС, чтобы убедиться, что среда такая же. Что может быть причиной этой странной проблемы?

Это мой 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:[email protected]') {
        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:[email protected]'
    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. Мой 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

Ответ 1

Класс AppWrapper не загружается, потому что интерфейс retrofit.ErrorHandler не включен в основной файл dex.

Как вы вычисляете, какие классы помещать в ваш файл файл-dex-list?
Там script, который может сгенерировать его для вас. Я написал blogpost, в котором показано, как его использовать.

Обновление (10/31/2014):
Gradle плагин v0.14.0 теперь делает это автоматически. См. Мой ответ здесь.

Обновление (24/04/2017):
В руководстве объясняется, как выбрать определенные классы с опцией gradle, если он не выбирает все правильные автоматически.

Ответ 2

если все выглядит нормально, но появляется эта ошибка,

попробуйте отключить мгновенный запуск!!!

когда я отключил его, все классы были загружены правильно.

Ответ 3

Если вы расширяете MultiDexApplication, вам не нужно делать вызов MultiDex.install(контекст), как это уже происходит (см. ссылку источника). Если вам нужно использовать attachBaseContext, просто убедитесь, что вы вызываете super.attachBaseContext(контекст).

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

Мы только что обновили developers.android.com с инструкциями о том, как использовать библиотеку поддержки с плагином Android gradle, включая оптимизацию разработки для быстрого цикла сборки разработки.

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

Ответ 4

Если кто-то попадет сюда, потому что их класс Application не найден на устройствах до Lollipop, но приложение отлично работает на Lollipop и выше, это, похоже, известная проблема с Jack и Multidex.

Ссылка: Jack Issue 213484

Ссылка: Jack Issue 224026

Ответ 5

NoClassDefFound может произойти с любым произвольным классом, который не загружался на устройстве с API раньше Lollipop и с поддержкой multidex. Если вы правильно настроили ProGuard, вы можете легко обойтись без дополнительных накладных расходов MultiDex, чтобы приложение медленно запускалось для ваших выпусков, особенно на старых устройствах. Однако вы не хотите, чтобы ProGuard замедлял работу, когда вы разрабатываете приложение в режиме отладки. Если вы попытаетесь запустить сборку отладки с отключенным ProGuard, вы начнете получать ошибки сборки, например, com.android.dex.DexIndexOverflowException: не может объединить новый индекс 72118 в инструкцию, отличную от jumbo!

Итак, что вы действительно хотите, это ProGuard enabled и multidex отключены только в сборках релизов, в то время как отладочные сборки должны быть противоположны с отключением Proguard и поддержкой multidex. Вы также должны быть разборчивы и использовать меньше зависимостей, конечно, потому что ваша версия release будет подвержена пределу 64K.

Для этого требуется установить build.gradle для конфигурации buildTypes и компиляции зависимостей библиотеки поддержки нескольких приложений только для отладки.

Подкласс приложения также должен быть установлен для другого подкласса в зависимости от того, находитесь ли вы в режиме мультидетекса или нет. Это может быть достигнуто с помощью принципа слияния манифеста градиента, путем определения манифеста переопределения для вашей сборки отладки и последующего указания вашего класса приложения по-разному.

Вот соответствующий модуль приложения build.gradle:

  android {
...   buildTypes {       debug {           minifyEnabled false//Отключено Proguard           multiDexEnabled true//Включение поддержки multi-dex.       }       выпуск {           minifyEnabled true//Enabled Proguard           proguardFiles getDefaultProguardFile ('proguard-android.txt'), 'proguard-rules.pro'           multiDexEnabled false//Отключить поддержку multi-dex.       }   }   зависимостей {       debugCompile 'com.android.support:multidex:1.0.1'//debugCompile делает его включенным только для отладочных сборников       ...   }
}
Код>

Если вы не используете подкласс приложения, все, что вам нужно сделать, это указать имя подкласса Application android.support.multidex.MultiDexApplication, как указано в https://developer.android.com/studio/build/multidex.html, но вы хотите сделать это только для вашей сборки отладки.

Для этого вам нужно указать переопределение файлов в иерархии папок версии отладки и версии, например:

<Предварительно > <код > ЦСИ   - главный       - AndroidManifest.xml       - java/com/yourcompany/MyApplication.java(распространяется от BaseApplication)   - выпуск       - java/com/yourcompany/BaseApplication.java(распространяется от приложения)   - отладка       - AndroidManifest.xml       - java/com/yourcompany/BaseApplication.java(распространяется от MultiDexApplication) Код >

Да, вы создаете папки debug и release рядом с папкой вашего основного модуля. Добавьте следующие файлы:

отлаживать /AndroidManifest.xml

  <? xml version = "1.0" encoding = "utf-8"? >
< manifest xmlns: android = "http://schemas.android.com/apk/res/android"   XMLNS: инструменты = "http://schemas.android.com/tools"   >   & Л; приложение       Android: name= "com.yourcompany.MyApplication"       Инструменты: заменить = "Android: имя" />
& Л; /& манифеста GT;
Код>

Этот манифест будет включен только в сборку отладки и будет проигнорирован для вашей версии.

релиз /Java/COM/yourcompany/BaseApplication.java

  Открытый класс BaseApplication расширяет Приложение {
}
Код>

отлаживать /Java/COM/yourcompany/BaseApplication.java

  Открытый класс BaseApplication расширяет MultiDexApplication {
}
Код>

главная /Java/COM/yourcompany/MyApplication.java

  открытый класс MyApplication расширяет BaseApplication {   @Override   public void onCreate() {       super.onCreate();       // Инициализация базы данных и т.д.;   }
}
Код>

Таким образом, вы можете добавить функциональность вашего приложения в MyApplication.java, имея разные базовые классы.

Ответ 6

У меня также возникла такая проблема. Решение в моем случае было: В моем файле build.gradle в зависимостях было несколько записей compile 'com.android.support:multidex:1.0.0'. как:

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

просто поместите только один компилятор 'com.android.support:multidex:1.0.0' как:

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

Ответ 7

Я, наконец, решил! Причина не в методе onCreate(). Эта линия от 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

Эта строка запускается перед всем журналом MultiDex. Источником проблемы был интерфейс Retrofit ErrorHandler, который реализуется AppWrapper.

Как сказал @AlexLipov в своем ответе, Dalvik просто не смог найти класс ErrorHandler и не смог загрузить AppWrapper.

В любом случае решение не реализовать ErrorHandler напрямую AppWrapper и вместо этого вставить его в закрытую переменную.

Ответ 8

Я пробовал много решений, но у меня никто не работал. Наконец я нашел это:

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

И был единственным решением для моей проблемы. Может быть, у кого-то такая же проблема, и это может помочь :)