'Ionic3 MainActivity ClassNotFoundException on Android 4.4 (Kitkat)

I have an app using Ionic 3 and Cordova-Android 6.4.0. The app works fine on Android API levels > 19 (Kitkat). But running the app on Android 4.4 causes the app to crash at startup with the following exception:

03-21 14:07:40.513 2408-2408/com.xxx.app.xxx E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xxx.app.xxx, PID: 2408
    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.xxx.app.xxx/com.xxx.app.xxx.MainActivity}: java.lang.ClassNotFoundException: Didn't find class "com.xxx.app.xxx.MainActivity" on path: DexPathList[[zip file "/data/app/com.xxx.app.xxx-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.xxx.app.xxx-2, /system/lib]]
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2121)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "com.xxx.app.xxx.MainActivity" on path: DexPathList[[zip file "/data/app/com.xxx.app.xxx-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.xxx.app.xxx-2, /system/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1061)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2112)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
        at android.app.ActivityThread.access$800(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 

I've read about the multidex fix, but I can't apply it to my Ionic app because I can't change the generated Java code to add MultiDex.install(this);.

Does anyone have a solution for this?



Solution 1:[1]

The problem and solution are described here.

The java.lang.ClassNotFoundException comes from the fact that the app and its libraries exceed 65,536 methods, and as a result the Java classes are spread across more than one DEX file (Dalvik EXecutable) within the app's APK, i.e. classes.dex, classes2.dex etc. Java classes required to start the app may end up in classes2.dex within the app's APK (as opposed to classes.dex), which can then not be loaded by the Dalvik runtime in Android versions less than 5. From the Android web site:

When building each DEX file for a multidex app, the build tools perform complex decision-making to determine which classes are needed in the primary DEX file so that your app can start successfully. If any class that's required during startup is not provided in the primary DEX file, then your app crashes with the error java.lang.NoClassDefFoundError.

The solution is to identify every class that is referenced at app startup in a text file, as described in the link at the start of my post.

However, the list of required classes is long and hard to establish. I got as far as the classes below, but there are still more startup classes to discover. My solution is to say "Sorry, this app is only available for Android 5 and later".

com/mycompany/app/myapp/MainActivity.class
org/apache/cordova/CallbackMap.class
org/apache/cordova/ConfigXmlParser.class
org/apache/cordova/CordovaActivity$1.class
org/apache/cordova/CordovaActivity.class
org/apache/cordova/CordovaInterface.class
org/apache/cordova/CordovaInterfaceImpl.class
org/apache/cordova/CordovaPreferences.class
org/apache/cordova/CordovaWebViewEngine.class
org/apache/cordova/engine/SystemWebViewEngine.class
org/apache/cordova/LOG.class
org/apache/cordova/PluginEntry.class
org/json/JSONException.class
org/json/JSONObject.class

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AndrWeisR