多平台项目:如何将generated源集类加入metadata工件?
这个问题我之前帮同行排查过类似的,核心就是Kotlin多平台(KMP)的metadata构件默认只包含commonMain源集的内容,而你自定义的generated源集没被关联到common侧的构建流程里,导致依赖项目的commonMain找不到这些生成类。给你几个可行的解决方案,按需选择:
方案1:把生成代码直接归到commonMain(最省心)
没必要单独维护generated源集,直接让kapt生成的代码成为commonMain的一部分,这样metadata自然会把这些类包含进去。
在你的build.gradle.kts里这么配置:
kotlin { sourceSets { val commonMain by getting { // 把kapt生成common代码的目录添加到commonMain的源码路径 kotlin.srcDir("build/generated/source/kaptKotlin/commonMain") } // 原来jvmMain、jsMain依赖generated的配置可以保留,或者如果不需要就删掉 val jvmMain by getting val jsMain by getting } } // 确保kapt先生成代码,再编译commonMain的元数据 tasks.named("compileCommonMainKotlinMetadata") { dependsOn(tasks.named("kaptCommonMainKotlin")) }
这样kapt生成的类会被当作commonMain的原生代码处理,编译后自动进入metadata工件,依赖项目的commonMain就能直接用了。
方案2:保留generated源集,关联到common侧构建
如果你想保留单独的generated源集,那就得调整源集依赖和任务执行顺序,打破循环依赖的问题:
kotlin { sourceSets { // 先定义generated源集 val generated by creating { kotlin.srcDir("build/generated/source/kaptKotlin/generated") // 让generated依赖commonMain的输出,因为kapt需要用common里的注解类 dependencies { implementation(commonMain.get().output) } } val commonMain by getting { // 让commonMain依赖generated,但得确保先生成代码再编译 dependsOn(generated) } // 原来jvm、js依赖generated的配置不变 val jvmMain by getting { dependsOn(generated) } val jsMain by getting { dependsOn(generated) } } } // 强制kapt生成代码后,再编译generated的元数据 tasks.named("compileGeneratedKotlinMetadata") { dependsOn(tasks.named("kaptCommonMainKotlin")) } // 确保generated编译完成后,再编译commonMain的元数据 tasks.named("compileCommonMainKotlinMetadata") { dependsOn(tasks.named("compileGeneratedKotlinMetadata")) }
这个方案通过明确任务执行顺序解决循环:先跑kapt处理commonMain的注解生成代码,再编译generated,最后编译依赖generated的commonMain,这样metadata里就会包含generated的类了。
方案3:直接给metadata jar塞generated类
如果前两个方案都不适合,还可以直接修改metadata构件的内容,把generated的编译产物加进去:
tasks.named<Jar>("kotlinMetadataJar") { // 把generated源集编译后的元数据产物添加到metadata jar里 from(tasks.named("compileGeneratedKotlinMetadata").map { it.outputs }) }
这种方式更直接,相当于手动把generated的类塞进metadata工件里,适合不想调整源集结构的场景。
几个要注意的点
- 确保kapt生成的代码是跨平台兼容的,不能有jvm/js专属的API,不然metadata里的类在跨平台依赖时会出问题。
- 如果用的Gradle版本比较新,任务名称可能有变化,比如
kaptCommonMainKotlin可能变成kaptGenerateStubsCommonMainKotlin,可以跑./gradlew tasks查看具体的任务名。 - 一定要检查任务依赖顺序,不然会出现编译时找不到生成类的情况。
内容的提问来源于stack exchange,提问作者jens
相关产品推荐
相关产品推荐

