Kotlin-JNI Help

➡️ Calling Native code from JVM

The @JniCall annotation is the core of the KSP module. It generates the necessary JNI boilerplate so you can write clean, idiomatic Kotlin code.

1. Define Your Kotlin/Native Function

Write your function using standard Kotlin types and annotate it with @JNICall.

// commonMain @JniCall expect fun mixed(number: Long, value: CharArray, upper: Boolean, char: Char): String // nativeMain or jniNativeMain actual fun mixed(number: Long, value: CharArray, upper: Boolean, char: Char): String return "$a, $b, $c, $d" }

2. Let KSP generate the JNI Stub

When you build the project, KSP will automatically generate:

  • actual functions for JVM/Android.

  • native function to do the heavy JNI work.

public actual fun mixed( number: Long, `value`: CharArray, upper: Boolean, char: Char, ): String = mixedExternal(number, `value`, upper, char) public external fun mixedExternal( number: Long, `value`: CharArray, upper: Boolean, char: Char, ): String
/** * Calling user function kni.test.Bridge.mixed * @param number kotlin.Long -> com.dshatz.kni.binding.jlong (via Simple) * @param value kotlin.CharArray -> com.dshatz.kni.binding.jcharArray (via Convertable) * @param upper kotlin.Boolean -> com.dshatz.kni.binding.jboolean (via Convertable) * @param char kotlin.Char -> com.dshatz.kni.binding.jchar (via Convertable) * * @return kotlin.String <- com.dshatz.kni.binding.jstring */ @CName("Java_kni_test_Bridge_mixedExternal") @OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class) public fun _mixedJNI( env: CPointer<JNIEnvVar>, clazz: jobject, number: jlong, `value`: jcharArray, upper: jboolean, char: jchar, ): jstring { // generated by Kotlin-JNI // this calls the actual fun you defined above in the native sourceset. val env = env.GetAndAttach()!! return (kni.test.Bridge.mixed( number, (`value`).toKCharArray(env)!!, (upper).toKBoolean(env)!!, (char).toKChar(env)!! )).toJString(env)!! }

3. Use in common code

Now you can call your mixed function from Android, JVM, Native or commonMain!

On non-native targets the call will be routed through JNI to your Native implementation.

fun main() { mixed(Long.MAX_VALUE, " - max value".toCharArray(), false, 'x') }
Last modified: 23 April 2026