MultiDex NoClassDefFound error

后端 未结 8 887
醉梦人生
醉梦人生 2020-11-29 05:52

I have converted my application into MultiDex to bear with 64k dex limit. Now it looks like this:

public class App extends MultiDexApplication {

private App         


        
8条回答
  •  北荒
    北荒 (楼主)
    2020-11-29 06:25

    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. 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. However, you don't want ProGuard slowing you down while you develop your app in debug mode. 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!

    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. You also have to be picky and use less dependencies, of course, because your release build will be subject to the 64K limit.

    This requires setting up build.gradle to have buildTypes configs, and compiling the multidex support library dependency only for debug.

    The Application subclass must also be set to derive from a different subclass depending on whether you're in multidex mode or not. 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.

    Here's the relevant app module 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.

    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. Add the following files within:

    debug/AndroidManifest.xml

    
    
        
    
    

    This manifest will only be included in debug builds, and will be ignored for your release one.

    release/java/com/yourcompany/BaseApplication.java

    public class BaseApplication extends Application {
    }
    

    debug/java/com/yourcompany/BaseApplication.java

    public class BaseApplication extends MultiDexApplication {
    }            
    

    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.

提交回复
热议问题