分层项目结构
Kotlin 跨平台项目支持分层的源代码集结构。
这意味着你可以安排一个中间源代码集的层级结构,以便在部分(但不是全部) 支持的目标 之间共享通用代码。使用中间源代码集有助于你:
为某些目标提供特定的 API。例如,一个库可以在中间源代码集中为 Kotlin/Native 目标添加原生特定的 API,而不为 Kotlin/JVM 添加这些 API。
为某些目标使用特定的 API。例如,你可以从 Kotlin 跨平台库为某些组成中间源代码集的目标提供的丰富 API 中受益。
在项目中使用平台相关的库。例如,你可以从中间 iOS源代码集访问 iOS 特定的依赖项。
Kotlin 工具链确保每个源代码集只能访问该源代码集编译的所有目标都可用的 API。
这可以防止出现像使用 Windows 特定的 API 然后将其编译为 macOS, 导致链接错误或运行时的未定义行为的情况。
设置源代码集层级的推荐方法是使用 默认层级模板。
该模板涵盖了最常见的情况。如果你有一个更高级的项目,你可以 手动配置。
这种方法更底层:它更灵活,但需要更多的努力和知识。
默认层级模板
从 Kotlin 1.9.20 开始,Kotlin Gradle 插件内置了一个默认的 层次结构模板。
该模板为一些常见的用例预定义了中间源代码集。
插件会根据项目中指定的目标,自动设置这些源代码集。
考虑以下示例:
当你在代码中声明 androidTarget
、 iosArm64
和 iosSimulatorArm64
这些目标时,Kotlin Gradle 插件会从模板中找到合适的共享源代码集并为你创建它们。最终的层级结构如下所示:
彩色的源代码集实际上是已创建并存在于项目中的,而灰色的源代码集则是来自默认模板并被忽略的。 例如,Kotlin Gradle 插件没有创建 watchos
源代码集,因为项目中没有 watchOS 目标。
如果你添加了一个 watchOS 目标,例如 watchosArm64
,那么 watchos
源代码集会被创建, apple
、 native
和 common
源代码集中的代码也会被编译到 watchosArm64
。
Kotlin Gradle 插件为默认层次结构模板中的所有源代码集提供了类型安全和静态访问器,因此与 手动配置 相比,可以在不使用 by getting
或 by creating
构造的情况下引用它们。
如果在未先声明相应目标的情况下尝试访问源代码集,您将看到一个警告:
额外配置
你可能需要对默认的层级模板进行调整。 如果你之前通过 dependsOn
调用 手动 引入了中间源代码集,这会取消默认层级模板的使用,并导致出现以下警告:
要解决这个问题,可以通过以下几种方式来配置你的项目:
替换手动配置
问题场景 :你所有的中间源代码集目前都由默认层级模板覆盖。
解决方案 :移除所有手动的 dependsOn()
调用和通过 by creating
构造的源代码集。
要查看所有默认源代码集的列表,请参见 完整的层级模板。
创建额外的源代码集
问题场景 :你想添加默认层级模板尚未提供的源代码集, 例如,在 macOS 和 JVM 目标之间添加一个源代码集。
解决方案:
通过显式调用
applyDefaultHierarchyTemplate()
重新应用模板。使用
dependsOn()
手动 配置额外的源代码集:kotlin { jvm() macosArm64() iosArm64() iosSimulatorArm64() // 再次应用默认层级模板。例如,它会创建 iosMain源代码集: applyDefaultHierarchyTemplate() sourceSets { // 创建一个额外的 jvmAndMacos源代码集: val jvmAndMacos by creating { dependsOn(commonMain.get()) } macosArm64Main.get().dependsOn(jvmAndMacos) jvmMain.get().dependsOn(jvmAndMacos) } }kotlin { jvm() macosArm64() iosArm64() iosSimulatorArm64() // 再次应用默认层级模板。例如,它会创建 iosMain源代码集: applyDefaultHierarchyTemplate() sourceSets { // 创建一个额外的 jvmAndMacos源代码集: jvmAndMacos { dependsOn(commonMain.get()) } macosArm64Main { dependsOn(jvmAndMacos.get()) } jvmMain { dependsOn(jvmAndMacos.get()) } } }
修改源代码集
问题场景 :您已经拥有与模板生成的源代码集完全相同的名称,但这些源代码集在项目中的不同目标集之间共享。 例如,一个 nativeMain
源代码集仅在特定于桌面的目标之间共享: linuxX64
、 mingwX64
和 macosX64
。
解决方案 :目前没有办法修改模板的源代码集之间的默认 dependsOn
关系。 源代码集的实现和含义,例如 nativeMain
,在所有项目中必须保持一致。
但是,您仍然可以执行以下操作之一:
查找适用于您的目的的不同源代码集,可能是在默认层级模板中或手动创建的源代码集中。
完全放弃模板,通过在
gradle.properties
文件中添加kotlin.mpp.applyDefaultHierarchyTemplate=false
并手动配置所有源代码集。
查看完整的层次结构模板
当您声明项目编译的目标时,插件根据模板中指定的目标选择共享源代码集,并在您的项目中创建这些源代码集。
手动配置
您可以手动在源代码集结构中引入一个中间源代码集。 它将保存多个目标的共享代码。
例如,如果您想在本地 Linux、Windows 和 macOS 目标 (linuxX64
、 mingwX64
和 macosX64
) 之间共享代码,可以按以下步骤操作:
添加中间源代码集
desktopMain
,该源代码集保存这些目标的共享逻辑。使用
dependsOn
关系指定源代码集的层级结构。
结果层级结构如下所示:
您可以为以下目标组合共享源代码集:
JVM 或 Android + JS + Native
JVM 或 Android + Native
JS + Native
JVM 或 Android + JS
Native
Kotlin 目前不支持为以下组合共享源代码集:
多个 JVM 目标
JVM + Android 目标
多个 JS 目标
如果您需要从共享的本地源代码集中访问平台特定的 API,IntelliJ IDEA 将帮助您检测可以在共享的本地代码中使用的公共声明。 对于其他情况,请使用 Kotlin 的 预期声明和实际声明 机制。