MultiDex NoClassDefFound error
Solution 1:
Your AppWrapper class fails to load because the retrofit.ErrorHandler interface is not included in main dex file.
How do you calculate which classes to put in your main-dex-list file?
There's a script that can generate it for you. I wrote a blogpost that shows how to use it.
Update (10/31/2014):
Gradle plugin v0.14.0 now does it automatically. See my answer here.
Update (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.
Solution 2:
if everything looks OK, but this error appears,
try to disable instant run!!!
when I disabled it all the classes were loaded properly.
Solution 3:
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). If you need to use attachBaseContext then just make sure to call super.attachBaseContext(context).
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.
https://developer.android.com/tools/building/multidex.html
Solution 4:
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.
Ref: Jack Issue 213484
Ref: Jack Issue 224026
Solution 5:
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
<?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
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.