Search code examples
androidkotlindalvik

Compiling Kotlin file to Dex generates ClassNotFoundException (kotlin.jvm.internal.Intrinsics)


I'm trying to create a command line script to run on my Android device. I'm following this answer to run the compiled kotlin file with Dalvik VM, but I'm getting the following error when I run dalvikvm -cp TestKt.zip on adb shell:

Exception in thread "main" java.lang.NoClassDefFoundError: Failed resolution of: Lkotlin/jvm/internal/Intrinsics;
    at TestKt.main(Unknown Source:2)
Caused by: java.lang.ClassNotFoundException: Didn't find class
"kotlin.jvm.internal.Intrinsics" on path: DexPathList[[zip file "TestKt.zip"],
nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64, 
/system/lib64, /system/vendor/lib64]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    ... 1 more

This is the simple file (Test.kt) that I'm trying to compile:

package edu.ufrn.lapps

fun main(args: Array<String>) {
    println(args.size);
}

I wrote a Makefile to compile it (mainly because this is just a test, but I'll probably move to Gradle once I need dependencies):

NAME := TestKt
OUTPUT := TestKt

PKG := edu/ufrn/lapps
KFLAGS := -include-runtime

D8C := $(HOME)/Android/Sdk/build-tools/29.0.1/d8
D8FLAGS := --no-desugaring 

dex:
    kotlinc src/$(PKG)/Test.kt
    $(D8C) $(D8FLAGS) $(PKG)/$(OUTPUT).class

zip: dex 
    zip $(OUTPUT).zip classes.dex

jvm:
    kotlinc $(SRC)/Test.kt $(KFLAGS) -d $(OUTPUT).jar

.PHONY: clean

clean:
    -rm -r META-INF/
    -rm $(OUTPUT).jar $(OUTPUT).zip

I'm trying to follow the AOSP cmds to make my CLI script, but I've never compiled Java bytecode to Dex before, so I'm not sure if this is the right way to do it.

How should I go about fixing this error?


Solution

  • I managed to compile the Kotlin source file into an acceptable Dex file. The tip by JesusFreke really helped and was the source of the problem.

    The kotlin compiler already generates Java bytecode targeting JRE6 by default, which is what Dalvik needs to run, so it was just a matter of including the kotlin runtime into the Dex file.

    Here is what I did:

    $ kotlinc src/edu/ufrn/lapps/Test.kt -include-runtime -d TestKt.jar 
    $ ~/sdk-patk/build-tools/29.0.1/d8 TestKt.jar --no-desugaring
    $ zip TestKt.zip classes.dex
    $ adb push TestKt.zip /sdcard/
    $ adb shell
    $ [on adb shell]: dalvikvm -cp /sdcard/TestKt.zip edu.ufrn.lapps.TestKt
    

    According to the d8 compiler documentation, the --no-desugaring is used to remove Java 8 features. Since the kotlin compiler targets JRE6 by default, desugaring is not needed.

    Some links that helped me: