Kotlin Native dependency is not accessible at runtime on the target platform

Hi.

I’m trying to create a shared library using Kotlin Native that will be used on Android and iOS.
I tried creating something simple just to check if it works and it partially did, partially didn’t.

  1. In Kotlin Native common source set, I’ve created a simple class (let’s say: Printer) with a simple function that prints anything using println (let’s say: printSomething).
  2. Built the project and got 3 jars as a result (like: printer-jvm-0.0.1.jar, printer-metadata-0.0.1.jar and printer-metadata-0.0.1-sources.jar)
  3. Manually copy-pasted the jars to the Android app’s libs directory.
  4. In Android app code, created an object and executed the printing function (like: Printer().printSomething()) - so far so good.

But since I need some kind of BigDecimal-like support in Kotlin Native library, I tried to use some external library to check how it is going to work like.

I imported it like this:

commonMain {
    dependencies {
        implementation kotlin('stdlib-common')
        implementation("com.ionspin.kotlin:bignum:0.1.6-1.3.72-SNAPSHOT")
    }
}

And I added something like this in my Kotlin Native common source set:

import com.ionspin.kotlin.bignum.decimal.BigDecimal
import com.ionspin.kotlin.bignum.decimal.DecimalMode
import com.ionspin.kotlin.bignum.decimal.RoundingMode

data class Percentage(val value: String) {
    val half get() = BigDecimal.parseStringWithMode(
        value,
        DecimalMode(
            decimalPrecision = 2,
            roundingMode = RoundingMode.ROUND_HALF_CEILING
        )
    ).toStringExpanded()
}

Then, in the Android app, I was able to write:

Percentage("1.00").half

But when the app was running and I executed that line of code, the app crashed:

07-23 15:54:51.868 4591-4591/com.example.app.stage E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.app.stage, PID: 4591
    java.lang.NoClassDefFoundError: Failed resolution of: Lcom/ionspin/kotlin/bignum/decimal/BigDecimal;
        at sample.Percentage.getHalf(Percentage.kt:8)
        at com.example.app.ui.SimpleViewModel.saveOrder(SimpleViewModel.kt:296)
        at com.example.app.ui.SimpleFragment$onViewCreated$4.invoke(SimpleFragment.kt:144)
        at com.example.app.ui.SimpleFragment$onViewCreated$4.invoke(SimpleFragment.kt:54)
        at com.example.app.ui.view.list.ListContainer$2.onClick(ListContainer.kt:48)
        at android.view.View.performClick(View.java:4780)
        at android.view.View$PerformClick.run(View.java:19866)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "com.ionspin.kotlin.bignum.decimal.BigDecimal" on path: DexPathList[[zip file "/data/app/com.example.app.stage-1/base.apk"],nativeLibraryDirectories=[/data/app/com.example.app.stage-1/lib/x86_64, /vendor/lib64, /system/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        at sample.Percentage.getHalf(Percentage.kt:8) 
        at com.example.app.ui.SimpleViewModel.saveOrder(SimpleViewModel.kt:296) 
        at com.example.app.ui.SimpleFragment$onViewCreated$4.invoke(SimpleFragment.kt:144) 
        at com.example.app.ui.SimpleFragment$onViewCreated$4.invoke(SimpleFragment.kt:54) 
        at com.example.app.ui.view.list.ListContainer$2.onClick(ListContainer.kt:48) 
        at android.view.View.performClick(View.java:4780) 
        at android.view.View$PerformClick.run(View.java:19866) 
        at android.os.Handler.handleCallback(Handler.java:739) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5254) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
    	Suppressed: java.lang.ClassNotFoundException: com.ionspin.kotlin.bignum.decimal.BigDecimal
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
        		... 16 more
     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

So I guess the jars produced by the Kotlin Native build do not include the dependencies for some reason and I have no clue what to do about it.

This is my whole build.gradle file in the Kotlin Native project (it was generated like this by IntelliJ IDEA, the only thing I changed was adding the dependency on the external Kotlin Native library for the BigDecimals).

plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '1.3.72'
}
repositories {
    mavenCentral()
    maven {
        url = uri("https://oss.sonatype.org/content/repositories/snapshots")
    }
}
group 'com.example'
version '0.0.1'

apply plugin: 'maven-publish'

kotlin {
    jvm()
    // This is for iPhone simulator
    // Switch here to iosArm64 (or iosArm32) to build library for iPhone device
    iosX64("ios") {
        binaries {
            framework()
        }
    }
    sourceSets {
        commonMain {
            dependencies {
                implementation kotlin('stdlib-common')
                api("com.ionspin.kotlin:bignum:0.1.6-1.3.72-SNAPSHOT")
            }
        }
        commonTest {
            dependencies {
                implementation kotlin('test-common')
                implementation kotlin('test-annotations-common')
            }
        }
        jvmMain {
            dependencies {
                implementation kotlin('stdlib')
            }
        }
        jvmTest {
            dependencies {
                implementation kotlin('test')
                implementation kotlin('test-junit')
            }
        }
        iosMain {
        }
        iosTest {
        }
    }
}
configurations {
    compileClasspath
}

Is this issue caused by some missing configuration in Gradle? Or do I have to do something specific on the Android app’s side to be able to use the jars produced by the Kotlin Native build? Or something else?

Maybe you have already fixed this issue since its been a week or so, but why did you use the api function in your dependency below?

Seems like it should have been

I’m in the process of trying this library out in a similar way, will know in a couple days if I have issues too :slight_smile: One challenge I’m having though is I don’t see how to convert a BigDecimal into any of the native types. I need a .toLong(), .toInt() etc and they don’t seem to exist. Am I missing something or am I gonna have to do extension functions?