如何在不使用胖JAR的情况下分发绑定C库的KMP JVM库?
KMP JVM目标分发方案(避免胖JAR)
针对你的KMP库JVM分发需求,以下是几种推荐的方案,均能避免打包全平台原生文件的胖JAR:
1. 按平台拆分JAR + 自动加载逻辑
- 核心思路:将JVM端的公共API打包成无原生代码的瘦JAR,同时为每个目标平台(如linux-x64、windows-x64、macos-x64/arm64)单独打包包含对应原生库(.so/.dll/.dylib)的平台专属JAR,命名时带上平台标识(例如
your-lib-jvm-linux-x64.jar)。 - 实现细节:在核心瘦JAR中编写原生库加载逻辑,通过
System.getProperty("os.name")和System.getProperty("os.arch")判断当前运行平台,自动匹配对应的库文件名,再通过System.loadLibrary()或自定义类加载器从类路径中加载原生库。 - 实际案例:SQLite JDBC驱动采用了类似模式——核心JDBC API包不包含任何原生库,不同平台的原生库单独打包,驱动初始化时会自动检测运行环境并加载对应平台的库文件。
2. 利用构建工具分类器(Classifier)分发
- 核心思路:借助Maven/Gradle的分类器特性,将核心库与各平台原生库分开发布。核心库不带分类器,平台专属库用分类器标识平台(如
linux-x64、win-x64)。 - 实现细节:在Gradle KMP项目中,为每个JVM平台变体配置单独的打包任务,生成带分类器的JAR。发布到Maven仓库时,平台专属库会以
your-lib-jvm-1.0.0-linux-x64.jar的形式存在。用户依赖时,只需先声明核心库依赖,再根据自身运行平台添加对应分类器的原生库依赖;也可以通过Gradle的属性配置实现自动匹配平台。 - 实际案例:libGDX框架的JVM端原生库分发采用了该模式,用户可根据开发/运行平台,按需引入对应分类器的原生依赖包。
3. 运行时动态下载原生库
- 核心思路:核心JVM库不包含任何原生文件,在首次初始化时检测当前平台,从可信远程仓库(如Maven Central、私有服务器)下载对应版本的原生库到本地临时目录,再加载使用。
- 实现细节:需要处理版本匹配、文件完整性校验(如SHA-256校验)、本地缓存(避免重复下载)等逻辑。可借助OkHttp等HTTP库实现下载,通过
System.load()加载本地临时文件。 - 注意事项:需考虑网络环境限制,同时要确保下载源的安全性,防止恶意文件注入。
额外注意事项
- 无论采用哪种方案,都要在核心库中添加完善的异常处理:当原生库加载失败时,给出明确提示,告知用户需要引入对应平台的原生依赖。
- 统一平台标识规则,比如将
os.name和os.arch映射为标准名称(如linux-x64、macos-aarch64),避免因系统属性差异导致的匹配错误。 - 在Gradle KMP项目中,可通过扩展
jvm目标的sourceSets和tasks,快速配置平台专属JAR的打包逻辑,比如为每个平台创建单独的变体任务。
内容的提问来源于stack exchange,提问作者xephosbot
相关产品推荐
相关产品推荐

