记录一下在Kotlin Native上嵌入资源的插件开发过程

AI智能摘要
本文介绍了作者为满足Kotlin Multiplatform项目需求,开发一款Gradle插件以实现在Kotlin Native二进制文件中嵌入资源的过程。插件通过扫描`resources`目录下的文件,将其自动生成包含资源数据的Kotlin源码(`ByteArray`),并编译进最终程序。插件同时提供了一个运行时API(`getResource`方法及`Resource`类),方便在代码中读取这些资源为字节数组或字符串,并可选支持使用作者自研的`kzlib`库进行压缩。此外,还可通过额外模块将资源保存至文件系统。
— AI 生成的文章内容摘要

起因

因为我开发的ROneBot框架需要一个项目模板生成器, 之前是Jvm的ktor但是因为项目已经迁移到了Multiplatform所以还得单独为这个模块设置Jvm的Kotlin插件这样写起来很不美观,于是我就搜索了一下
在native二进制文件中嵌入资源的东西,然后就找到了kMBed这个插件, 但是这个插件作者的maven仓库被墙了,我把项目拉下来自己发布到自己的仓库但是不生效, 我恍然大悟原来可以开发一个gradle插件
然后识别resources内的资源文件将其作为byteArrayOfkotlin源码最后经过kotlin编译器编译生成的代码来实现"嵌入"到二进制文件内。

gradle插件

首先就是gradle插件了,由于只是获取resources内的资源文件并不需要扫描源码所以就不用ksp或者kcp了,创建一个设置里面可以设置kmp不同源码集的resources路径, 然后注册一个任务,将这些路径内的资源文件全部生成为.kt文件源码,说白了就是简单的源码生成器

运行时

既然生成了一个资源map,那肯定得提供一个简单的API来将其快捷的转换成字符串或者ByteArray, 当然如果所有东西都在内存操作的话是不需要额外的io库的,下面是Resource类的具体实现

public class Resource(uSource: UByteArray, private val compressed: Boolean = false) {
    private val source = uSource.toByteArray()

    public fun asByteArray(): ByteArray = if (compressed) source.zlibDecompress() else source

    public fun asString(): String {
        return asByteArray().decodeToString()
    }
}

gradle插件会生成一个Map,map的键就是resources下的路径+文件名,值就是Resource对象, 当然也可以配置zlib压缩, 这个zlib压缩的库是我自己实现的使用到了posix + cinterop的API

这里是zlib的仓库地址 https://github.com/RTAkland/kzlib 这个库除了android(native) 、 js 、wasmJs不支持外其余所有的target都是支持的

gradle插件除了会生成一个map还会附带一个方法 这个方法的签名如下

public fun getResource(path: String): Resource

传入路径即可获取Resource对象, 再调用Resource内的两个方法即可转换成不同的类型

文件系统运行时

如果还想将这个资源文件保存到文件系统来减少内存占用可以引入这个模块,此模块由kotlinx-io驱动,
对Resource对象添加了一个拓展函数

public fun Resource.saveTo(path: Path)

最后

这个插件的仓库地址是 https://github.com/RTAkland/KEmbeddableResources 具体如何配置的话看README即可, 使用非常简单

温馨提示:

1.本站大部分内容均收集于网络!若内容若侵犯到您的权益,请发送邮件至:xiaoman1221@yhdzz.cn,工作室将第一时间处理!

2.资源所需价格并非资源售卖价格,是收集、整理、编辑详情以及本站运营的适当补贴,并且本站不提供任何免费技术支持。

3.所有资源仅限于参考和学习,版权归原作者所有。

Kotlin

记录一下使用Compose multiplatform for web的使用

2025-3-11 22:29:12

Kotlin

记录一下Kotlin CInterop的使用

2025-4-19 1:35:32

38 条回复 A文章作者 M管理员
  1. Bear巨熊

    居然真有人愿意折腾KN构建链,respect

  2. 邪神之触

    想问下这个和externalResource比有啥优势啊

  3. 暗巷诗人

    如果资源文件特别多,编译速度影响大不大?

  4. 流光梦语

    之前用kMBed被墙搞怕了,楼主这自建方案靠谱👍

  5. Sea海

    iOS模拟器支持吗?看target列表有点懵

  6. 能量外放

    zlib自己实现确实稳,回头研究下posix调用细节

  7. 摄魂使者

    这个方案比硬编码优雅多了,省了不少事

  8. 长发公主

    能不能支持按build type嵌不同资源啊,debug模式不想带大文件

  9. 像素暴徒

    666 居然真有人愿意碰Kotlin Native的构建链

  10. 温柔如水

    这个Resource API设计得蛮干净,没啥多余的东西

  11. 毕方

    之前用Java那边的resource打包习惯了,转native真不适应

  12. 冰河世纪

    蹲个更新,最好加个sample项目,新手友好点

  13. 狡狐千面

    写的啥啊说了半天没讲清楚怎么引入依赖

  14. 啊嘛呢吧,又是KMP各种适配,头都大了

  15. 龟隐尘

    那要是想换别的压缩算法呢,比如lz4,能扩展吗?

  16. 喧闹小太阳

    感觉比kMBed靠谱,至少仓库能访问,文档也清楚

  17. 快乐小精灵

    刚试了下Android和macOS都正常,iOS真机待测,先收藏一波

  18. AI哨兵

    这个saveTo拓展好贴心,终于不用自己写输出流了

  19. HaruBloom

    话说如果资源特别大,编译出来包体积膨胀严重吗?求个实测数据

  20. 安静小太阳

    不是吧,又来一个gradle插件?配置一次能用一年还是算了吧

  21. 月下幽灵

    楼主这个zlib实现看着稳,回头去翻翻源码学习下posix调用

  22. 我之前也整过类似的,用cinterop直接绑二进制段,结果跨平台全跪了😭

  23. 听说kotlin native内存管理挺 tricky 的,这样塞一堆资源会不会容易炸?

  24. YukiFrost

    这方法绝了,比搞一堆externalResource舒服多了

  25. 那如果是动态加载资源呢?还是只能编译时嵌进去?

  26. KiriMist

    我之前也踩过kMBed仓库被墙的坑,楼主这方案靠谱👍

  27. 说白了就是把文件转成byteArray塞进代码里呗,但确实实用

  28. 梦幻仙境

    蹲个后续,打算用在自己的项目里试试

  29. 柚子晴

    又是gradle插件…每次配都头大,有没有更傻瓜的方式?

    • 夜枭鸣

      现在确实只能编译时嵌入,动态加载得另搞套机制,比如远程拉取或者本地文件读取

  30. 纸落云烟

    感觉还行,比硬编码舒服多了

  31. zlib自己实现的?牛啊,不过posix兼容性咋样

  32. 智慧Leo

    前几天刚折腾KMP资源嵌入,要是早看到这个就好了🤔

    • 人间透明

      同踩过这坑,折腾了一整天才发现资源路径大小写敏感问题,气死

  33. 霜华皇后

    求问支持iOS模拟器吗?看target列表有点懵

    • 冷眼傲世

      支持的,iOS模拟器用的是x64目标,插件里已经包含这个target了,放心用

  34. 竹间清欢

    这插件思路挺巧的,省得搞外部资源了

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索