Ошибка MultiDex NoClassDefFound

19

Я конвертировал свое приложение в 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.access00(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: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. Мой файл 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.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
    
задан 4emodan 30.10.2014 в 15:21
источник

7 ответов

10

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

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

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

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

    
ответ дан Alex Lipov 30.10.2014 в 17:11
источник
  • Спасибо, я попробую ваш скрипт. Но AppWrapper уже находится в файле main-dex-list (я добавил его к вопросу). Однако, похоже, это игнорируется. –  4emodan 31.10.2014 в 09:36
  • Ваш AppWrapper реализует интерфейс retrofit.ErrorHandler, который также должен быть помещен в основной файл. Dalvik не может разрешить интерфейс и, таким образом, не может загрузить ваш класс AppWrapper. –  Alex Lipov 31.10.2014 в 10:19
  • @AlexLipov да, это было так, я наткнулся на него, но не мог понять, почему это происходит. Спасибо за объяснение! –  4emodan 31.10.2014 в 11:37
6

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

Ссылка

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

Ссылка

    
ответ дан PaulR 03.11.2014 в 20:32
источник
  • При попытке реализовать Multidexing я запускаю исключение переполнения. Я уже разместил его здесь: stackoverflow.com/questions/26763702/... –  Roberto Betancourt 05.11.2014 в 19:28
5

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

Ссылка: Jack Issue 213484

Ссылка: Jack Issue 224026

    
ответ дан Thomas Sunderland 02.11.2016 в 15:15
источник
  • Спасибо! Это решило мою проблему. Вы должны отключить jack-компилятор и вместо этого использовать github.com/event/gradle-retrolambda. –  Rockney 27.01.2017 в 10:22
4

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

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

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

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

Вот соответствующий модуль приложения 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
        ...
    }
}

Если вы не используете подкласс приложения, все, что вам нужно сделать, это указать имя подкласса Application android.support.multidex.MultiDexApplication , как указано в Ссылка , но вы хотите сделать это только для своей сборки отладки.

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

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)

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

отлаживать / 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>

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

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

public class BaseApplication extends Application {
}

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

public class BaseApplication extends MultiDexApplication {
}            

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

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

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

    
ответ дан Dhiraj Gupta 01.06.2017 в 20:27
источник
  • Это может случиться и на устройствах, более новых, чем Lollipop ... –  Igor Ganapolsky 17.07.2017 в 22:42
4

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

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

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

    
ответ дан dvrm 05.07.2017 в 09:45
источник
1

У меня также возникла такая проблема. Решение в моем случае было: В моем файле 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 ........
}
    
ответ дан singh.indolia 29.05.2017 в 13:09
источник
0

Я, наконец, решил! Причина не в методе 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 class и не смог загрузить AppWrapper .

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

    
ответ дан 4emodan 31.10.2014 в 11:28
источник