能否将Kotlin-Native项目作为库用于Kotlin-JVM项目?附JNI方案咨询
问题解答
一、Kotlin-Native作为库直接在Kotlin-JVM项目中使用的现状
目前无法直接将纯Kotlin-Native库作为依赖引入Kotlin-JVM项目——Kotlin-Native编译产物是平台特定的原生二进制(比如Windows的.dll、Linux的.so、macOS的.dylib/.framework),而JVM只能识别字节码(.class/.jar),两者运行时环境完全不同,没有直接兼容机制。你看到的三年前讨论提到的“后续支持”,目前官方仍未实现直接跨运行时的库引用能力,官方文档也确实没有相关说明。
不过,借助Kotlin Multiplatform (KMP) 可以实现你设想的项目结构,达成“共享核心逻辑、用Native实现平台特定代码、JVM应用调用”的目标,这也是官方推荐的替代JNI/JNA的方案。
二、基于Kotlin Multiplatform的实现方案
你的项目结构可以调整为标准KMP项目,让core成为多平台共享模块,native-lib作为Native目标的实现,application作为JVM目标的应用:
调整后的项目结构
project - application (JVM目标) - 依赖core的JVM变体,以及其他JVM库 - core (多平台共享模块) - 包含通用类型、接口、共享业务逻辑 - 依赖Kotlin标准库的多平台版本 - native-lib (Native目标实现,可整合进core的native源集) - 实现core中定义的平台相关接口 - 对应不同平台(linuxX64、macosX64、mingwX64等)的原生代码
关键配置说明
- core模块配置:在
build.gradle.kts中声明多平台目标,包含JVM和所需的Native平台:
plugins { kotlin("multiplatform") version "1.9.20" } kotlin { jvm { compilations.all { kotlinOptions.jvmTarget = "17" } withJava() } linuxX64("native") // 根据需要添加其他平台,如macosX64、mingwX64 sourceSets { val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) } } val jvmMain by getting { dependencies { implementation(kotlin("stdlib-jdk8")) } } val nativeMain by getting { dependencies { implementation(kotlin("stdlib-native")) } } } }
- 共享逻辑与平台实现:在
core/src/commonMain/kotlin中定义接口:
// core/src/commonMain/kotlin/com/example/PlatformService.kt expect interface PlatformService { fun nativeOperation(input: String): String }
在Native源集实现该接口:
// core/src/nativeMain/kotlin/com/example/PlatformService.kt actual class PlatformServiceImpl : PlatformService { actual override fun nativeOperation(input: String): String { // 编写Kotlin-Native原生逻辑,比如调用系统API、C库等 return "Native processed: $input" } }
- JVM应用调用:在
application模块中依赖core的JVM变体,直接调用共享接口:
// application/src/main/kotlin/com/example/App.kt fun main() { val service = PlatformServiceImpl() println(service.nativeOperation("Hello from JVM")) }
三、纯Kotlin-Native库通过JNI绑定调用的方法
如果你的native-lib是独立的Kotlin-Native项目,需要让JVM代码调用它,需手动创建JNI绑定,步骤如下:
1. 编译Kotlin-Native库为JNI兼容的原生库
在Kotlin-Native项目的build.gradle.kts中配置:
plugins { kotlin("multiplatform") version "1.9.20" } kotlin { linuxX64("native") { compilations.getByName("main") { cinterops.create("jni") { // 配置JNI头文件路径,根据系统调整 includeDirs("/usr/lib/jvm/default-java/include") includeDirs("/usr/lib/jvm/default-java/include/linux") } } binaries { sharedLib { baseName = "nativelib" linkerOpts("-shared", "-fPIC") } } } }
2. 编写Kotlin-Native的JNI暴露函数
用@CName注解暴露符合JNI规范的函数:
// native-lib/src/nativeMain/kotlin/com/example/NativeLib.kt import kotlinx.cinterop.CPointer import kotlinx.cinterop.toKString @CName("Java_com_example_NativeBridge_nativeOperation") fun nativeOperation(env: CPointer<JNIEnv>, thiz: jobject, input: jstring): jstring { val inputStr = env.pointed.GetStringUTFChars!!(env, input, null)?.toKString() ?: "" val result = "JNI processed: $inputStr" env.pointed.ReleaseStringUTFChars!!(env, input, inputStr) return env.pointed.NewStringUTF!!(env, result) }
3. 在JVM项目中创建JNI桥接类
声明native方法并加载原生库:
// application/src/main/kotlin/com/example/NativeBridge.kt class NativeBridge { init { System.loadLibrary("nativelib") // 加载编译好的原生库 } external fun nativeOperation(input: String): String } // 使用示例 fun main() { val bridge = NativeBridge() println(bridge.nativeOperation("Hello JNI")) }
4. 编译与运行
- 先编译Kotlin-Native项目,生成共享库(如
libnativelib.so、nativelib.dll) - 将原生库放入JVM项目的资源目录或系统库路径
- 编译并运行JVM项目,确保JVM能找到原生库
内容的提问来源于stack exchange,提问作者user8681
相关产品推荐
相关产品推荐

