KMP构建范式升级:从Gradle DSL到Amper声明式配置 1. 项目概述KMP 默认项目结构变革的本质不是“换壳”而是构建范式的迁移JetBrains 官宣 KMP 全新默认项目结构这个消息在 Kotlin 跨平台开发者圈子里炸开时很多人第一反应是“又改 Gradle 配置了”、“是不是又要重写 build.gradle.kts”、“Amper 到底是个啥跟 Compose Multiplatform 有啥关系”——这些疑问背后藏着一个被长期低估的事实过去五年里KMP 项目的痛苦80% 不来自 Kotlin 语言本身而来自 Gradle 构建系统的结构性失配。我们一直用一个为单平台 Java 项目设计的、高度可配置但极度脆弱的构建系统去强行支撑多平台、多生命周期、多依赖策略的复杂工程。这次官宣不是一次小修小补而是 JetBrains 正式承认Gradle DSL 已经成为 KMP 大规模落地的最大瓶颈必须用更上层、更声明式、更面向领域Domain-Oriented的抽象来接管。核心关键词KMP、Amper、Gradle、Android Gradle Plugin在这里不是并列关系而是存在清晰的演进链条KMP 是目标Gradle 是当前工具Amper 是下一代构建范式而 Android Gradle PluginAGP是这场变革中最具张力的“既得利益者”与“最大阻力源”。你看到的“默认项目结构变化”表象是settings.gradle.kts里多了一行enableFeaturePreview(VERSION_CATALOGS)或是build.gradle.kts里少了一堆android { }块但内核是 JetBrains 正在把构建逻辑的控制权从 Gradle 的 imperative命令式脚本逐步移交到 Amper 的 declarative声明式配置中。这不是“能不能用”的问题而是“该不该这样写”的范式之争。对于 Android 开发者这意味着你熟悉的android { compileSdk 34 }可能会变成platforms.android.compileSdk 34这样的语义化字段对于 iOS 开发者cocoapods { ... }的嵌套 DSL 将被dependenciesios { ... }这种平台感知的扁平化语法取代。它解决的不是“如何让 iOS 和 Android 共享代码”而是“如何让一个工程师不用同时精通 Gradle Groovy、Kotlin DSL、AGP 版本兼容矩阵、Xcode 构建阶段钩子、CocoaPods 依赖解析原理就能可靠地交付一个跨平台模块”。这才是它值得被冠以“官宣”二字的根本原因——它标志着 KMP 从“技术可行”正式迈入“工程可用”的分水岭。2. 内容整体设计与思路拆解为什么必须放弃 Gradle DSL 的“自由”拥抱 Amper 的“约束”2.1 旧结构的“自由”实为枷锁Gradle DSL 的三大反模式要理解新结构的价值必须先看清旧结构的病灶。过去 KMP 项目普遍采用的 “Gradle Multi-Project 手动 platform block” 模式表面看灵活无比实则暗藏三重反模式每一种都在 silently 消耗团队生产力第一重反模式平台配置的“散装化”与“重复劳动”一个典型的shared/build.gradle.kts文件里你会看到这样的代码kotlin { jvm() androidTarget { publishAllLibraryVariants() } iosX64() iosArm64() iosSimulatorArm64() macosX64() macosArm64() // ... 还有 tvOS, watchOS, Windows, Linux }这看似只是几行声明但每个iosX64()调用背后都隐含着对 Xcode 工具链、SDK 版本、bitcode 设置、framework 导出策略的默认值继承。当你的团队需要为 iOS 17 强制启用 Swift Concurrency 支持时你必须在每一个iOS target 的闭包里手动添加binaries.framework { ... }并且确保所有 target 的配置完全一致。这种“复制粘贴式配置”在 3 个平台时还能忍受在 7 个平台时就是灾难。Amper 的platforms: [ iosArm64, iosSimulatorArm64 ]语法其精妙之处在于将“平台集合”本身作为一个一等公民所有公共配置如 SDK 版本、编译器标志只需定义一次自动广播到所有成员。这不是偷懒而是将“平台一致性”从一项需要人工校验的软性要求升级为由工具链强制保障的硬性契约。第二重反模式依赖管理的“上下文迷失”这是最让新人崩溃的点。在旧结构中一个implementation(com.squareup.okhttp3:okhttp:4.12.0)依赖究竟会被哪个平台使用答案是取决于它写在哪个sourceSets的dependencies块里。androidMain、iosMain、commonMain、jvmMain……这些 source set 名称本身就是一个认知负担。更糟的是当你想为 Android 添加一个仅限于debug构建的依赖比如com.facebook.stetho:stetho:1.6.0你必须写androidMain.dependencies { implementation(...) }而这个androidMain并非一个物理目录而是 Gradle 在内存中动态创建的抽象概念。Amper 的dependenciesandroid语法用符号直白地宣告了“此依赖的作用域”它不再需要你去记忆 source set 的命名规则和继承关系而是让你像写自然语言一样思考“这个库只给 Android 用”。第三重反模式构建生命周期的“不可见性”与“不可控性”Gradle 的构建生命周期Initialization → Configuration → Execution对 KMP 来说过于粗粒度。当你执行./gradlew build时Gradle 会为所有平台生成所有变体variants的 task哪怕你此刻只想测试 iOS 模拟器的 debug 包。旧结构无法优雅地表达“我只要构建 iOS Arm64 的 release framework”只能靠--include-build或复杂的 task 过滤。Amper 的build命令则天生支持--platform iosArm64 --variant release这样的细粒度指令因为它将“平台”和“变体”作为构建命令的一等参数而非隐藏在 Gradle task 名称里的后缀。这种可见性直接转化为 CI/CD 流水线的可预测性和资源利用率——你可以精确地为每个 PR 触发最小集的构建任务而不是每次都要跑满 20 个平台组合。2.2 Amper 的设计哲学用“领域特定语言DSL”替代“通用脚本语言”Amper 的本质是一个为 Kotlin Multiplatform 量身定制的领域特定语言DSL。它的设计哲学与 Gradle 截然不同Gradle 是“通用构建引擎”它不预设你的项目类型所以它提供的是Task、Configuration、Project这些底层原语让你自己拼凑出构建逻辑。这就像给你一堆乐高积木然后说“请造一辆能跑的车”。KMP 开发者花了大量时间在拼装“车轮”配置 Android target、“方向盘”设置 iOS framework、“发动机”管理 Kotlin/Native 编译器上却没时间真正驾驶这辆车开发业务逻辑。Amper 是“KMP 构建方案”它预设了你的项目就是 KMP所以它提供的是product、platforms、dependenciesplatform这些高层概念。它不是给你积木而是给你一套已经预装好引擎、轮胎、方向盘的“车模套件”你只需要选择颜色平台、加点油依赖、设定目的地构建目标。product.type: kmp/lib这一行就比plugins { id(org.jetbrains.kotlin.multiplatform) }更精准地表达了你的意图——你不是一个在玩 Gradle 插件的工程师你是一个在交付跨平台库的产品工程师。这种范式迁移带来的最大红利是可维护性的指数级提升。在一个拥有 5 个平台、12 个模块的大型 KMP 项目中旧结构的build.gradle.kts文件平均长度超过 800 行且高度耦合而 Amper 的module.yaml文件通常稳定在 150 行以内且每个 sectionproduct,dependencies,settings职责单一、边界清晰。当新成员加入时他不需要花三天时间去理解 Gradle 的afterEvaluate钩子何时触发他只需要打开module.yaml就能在 30 秒内找到“这个库支持哪些平台”、“它依赖了哪些第三方”、“它启用了哪些 Kotlin 特性”。这种降低的认知负荷是任何技术文档都无法替代的生产力。2.3 与 Android Gradle PluginAGP的共生与博弈提到 KMP就绕不开 AGP。这次结构变革AGP 是最微妙的参与者。一方面Amper 的崛起并非要取代 AGP——恰恰相反它需要 AGP 提供的成熟 Android 构建能力APK/AAB 打包、ProGuard/R8 混淆、Instant Run 等。Amper 的platforms.android配置块最终仍会翻译成对 AGP 的调用。但另一方面Amper 正在悄然重构 AGP 在 KMP 项目中的角色定位从“主导者”变为“协作者”在旧结构中android { }块是kotlin { }的兄弟节点两者平起平坐甚至因为 AGP 的历史包袱更重它常常在事实上主导了整个项目的构建流程比如compileSdk的版本会强制影响 Kotlin 的 JVM 目标版本。在 Amper 结构中platforms.android是product的一个属性它明确地处于“为 KMP 产品服务”的从属地位。AGP 的强大能力被封装在android这个命名空间下开发者无需再直面androidComponents、applicationVariants这些 AGP 内部 API。从“版本紧耦合”走向“版本松解耦”这是最实际的痛点。旧结构中KMP 项目必须小心翼翼地匹配 Kotlin 版本、Kotlin/Native 编译器版本、AGP 版本、Gradle 版本这四者的兼容矩阵。一个AGP 8.4可能只支持Gradle 8.6而Gradle 8.6又可能要求Kotlin 1.9.20但你的kotlin-multiplatform插件又只兼容Kotlin 1.9.10……这种“版本多米诺骨牌”让升级成为一场噩梦。Amper 通过在其 CLI 中内置版本协调器Version Resolver将这种复杂的依赖关系下沉到工具链内部。开发者只需声明kotlin: 1.9.20和agp: 8.4Amper 会自动计算出它们所需的 Gradle 版本并为你下载、配置、甚至验证其兼容性。你不再需要去查 JetBrains 的官方兼容性表格因为那个表格已经变成了 Amper 的一个内部函数。提示如果你正在维护一个混合了纯 Android App 和 KMP 模块的项目不要急于将整个项目迁移到 Amper。建议采用“渐进式共存”策略新开发的 KMP 模块一律使用 Amper 结构而遗留的 Android App 模块继续使用传统 AGP 结构。Amper 生成的.klib或.jar产物可以像任何标准 Maven 依赖一样被传统build.gradle.kts引入。这种混合模式已被 JetBrains 官方文档明确支持是目前最平滑的过渡路径。3. 核心细节解析与实操要点从build.gradle.kts到module.yaml的关键映射3.1 项目骨架的物理重构文件系统与模块边界的重新定义迁移到新结构第一步不是改代码而是重构你的磁盘目录。旧 KMP 项目典型的物理结构是my-kmp-project/ ├── settings.gradle.kts # 定义所有子项目 ├── build.gradle.kts # 根项目的通用配置如仓库 ├── shared/ │ ├── build.gradle.kts # 核心 KMP 模块包含 kotlin { } 块 │ └── src/ │ ├── commonMain/ │ ├── androidMain/ │ └── iosMain/ ├── app-android/ │ └── build.gradle.kts # Android App 模块 └── app-ios/ └── build.gradle.kts # iOS App 模块而 Amper 结构则强制推行一种更扁平、更语义化的布局my-kmp-project/ ├── module.yaml # 新结构的“心脏”取代所有 build.gradle.kts ├── src/ │ ├── commonMain/ # 共享代码 │ ├── androidMain/ # Android 特定代码 │ └── iosMain/ # iOS 特定代码 ├── app-android/ # Android App现在是一个独立的 Amper 项目 │ └── module.yaml └── app-ios/ # iOS App同样是一个独立的 Amper 项目 └── module.yaml关键变化在于module.yaml是唯一的构建入口它取代了build.gradle.kts和settings.gradle.kts的双重职责。一个module.yaml文件就完整定义了一个 KMP 模块的全部构建契约。src/目录成为模块根目录不再需要shared/src/这样的嵌套。src/commonMain直接位于项目根目录下这与 IntelliJ IDEA 的默认源码根目录设置完美契合避免了 IDE 频繁提示“Source root not found”。App 模块升格为独立项目app-android和app-ios不再是my-kmp-project的子模块而是与my-kmp-project并列的、拥有自己module.yaml的顶级项目。它们通过dependencies声明来引用my-kmp-project的产物实现了真正的“项目即依赖Project-as-Dependency”理念。这极大地简化了依赖版本管理——你不再需要在settings.gradle.kts里用includeBuild也不需要发布到 Maven 仓库Amper 会自动处理本地项目间的符号链接和增量编译。3.2module.yaml核心字段详解一份可执行的“产品说明书”module.yaml不是配置文件而是一份可执行的“KMP 产品说明书”。它的每个字段都对应着一个明确的工程决策。以下是对一个生产级module.yaml的逐行解读# product: 定义这个模块的“身份”和“使命” product: # type: kmp/lib 是最常见类型表示这是一个跨平台库 # 其他可选值kmp/app (跨平台应用), kmp/framework (iOS framework) type: kmp/lib # name: 库的逻辑名称用于依赖声明如 com.example:my-shared-lib name: my-shared-lib # version: 语义化版本号Amper 会自动将其注入到生成的 pom.xml 和 .klib 元数据中 version: 1.0.0 # platforms: 定义这个库“服务谁”即支持的目标平台 platforms: # 列出所有需要构建的平台。Amper 会为列表中的每个平台生成对应的二进制产物 - jvm - android - iosArm64 - iosSimulatorArm64 - macosX64 # 注意这里没有 windowsX64 或 linuxX64意味着这个库不打算支持桌面端 # 这种显式声明比在 build.gradle.kts 里注释掉某行 target 更加安全和自解释 # dependencies: 定义“这个库需要什么”即所有平台共享的依赖 dependencies: # $compose.foundation 是 Amper 内置的 Compose Catalog它会自动解析出 # 对应平台的正确坐标如 Android 上是 androidx.compose.foundationiOS 上是 compose-foundation-ios - $compose.foundation: exported # exported 关键字表示这个依赖不仅供本模块使用还会“透传”给所有依赖本模块的下游项目 # 这是实现“依赖传递”的关键等价于 Gradle 的 api() 配置 - $compose.material3: exported # 第三方 Maven 依赖语法与 Gradle 完全一致 - kotlinx.coroutines:coroutines-core:1.7.3: exported # dependenciesandroid: 定义“只给 Android 用的依赖” dependenciesandroid: # 这些依赖只会在 Android 平台的 classpath 中出现不会污染 iOS 或 JVM 的构建 - androidx.activity:activity-compose:1.7.2: exported - androidx.appcompat:appcompat:1.6.1: exported # 注意这里没有写 androidx.core:core-ktx因为它是 Kotlin/JVM 依赖 # 已经被包含在 $compose.foundation 的 transitive 依赖中无需重复声明 # settings: 定义“这个库怎么构建”即全局构建选项 settings: # kotlin: Kotlin 语言和编译器相关的设置 kotlin: # serialization: json 启用 Kotlin SerializationAmper 会自动添加必要的插件和依赖 serialization: json # multiplatform: true 是默认值但显式写出可提高可读性 multiplatform: true # compose: Compose Multiplatform 的专用设置 compose: # enabled: true 是启用 Compose 的开关Amper 会据此决定是否生成 Compose 相关的源码和资源 enabled: true # compiler: 指定 Compose Compiler 的版本Amper 会自动匹配 Kotlin 版本 compiler: 1.5.3 # android: Android 平台专属设置直接映射到 AGP 的功能 android: # compileSdk: 34Amper 会将其传递给 AGP并确保 Kotlin 的 JVM 目标版本与之兼容 compileSdk: 34 # minSdk: 21同理Amper 会检查其与 Kotlin/Native 的最低支持版本是否冲突 minSdk: 21注意module.yaml中的exported关键字是理解 Amper 依赖模型的核心。它取代了 Gradle 的api/implementation/compileOnly三元组。Amper 认为在 KMP 场景下绝大多数依赖都应该被导出exported因为共享模块的目的是为了被复用而复用者往往也需要其依赖的 API。只有极少数情况如kotlin-test这类仅用于测试的依赖才应该省略exported使其作用域严格限制在本模块内。3.3 与现有生态的兼容性Gradle、Maven、IDE 如何无缝衔接一个新工具能否成功不在于它有多炫酷而在于它能否“活在旧世界里”。Amper 在设计之初就将兼容性置于首位Gradle 的“隐身”支持Amper CLI 本身并不排斥 Gradle。当你运行amper build时它内部会启动一个轻量级的 Gradle 实例通常是 Gradle Wrapper并动态生成一个临时的build.gradle.kts文件然后将module.yaml中的声明翻译成 Gradle DSL 调用。这意味着你仍然可以使用./gradlew tasks查看所有可用的 task它们的名称如compileKotlinJvm与旧结构完全一致。你依然可以在module.yaml之外编写自定义的 Gradle task例如一个上传到私有 Nexus 的 task只需在module.yaml的settings.gradle字段中指定一个额外的init.gradle.kts文件即可。最重要的是你的 CI/CD 流水线几乎不需要修改。./gradlew build命令依然有效Amper 只是让它变得更智能、更可靠。Maven 仓库的“零摩擦”发布Amper 内置了amper publish命令它会自动为每个平台生成符合 Maven 规范的pom.xml文件包含正确的packaging和classifier。将jvm平台的.jar、android平台的.aar、iosArm64平台的.klib等产物打包进一个统一的*-all.zip发布包。自动生成maven-metadata.xml支持 Maven 的版本范围解析如1.0.。 这意味着一个使用 Amper 构建的 KMP 库可以被任何传统的 Maven 或 Gradle 项目用最标准的方式引入无需任何额外插件或配置。implementation(com.example:my-shared-lib:1.0.0)这行代码在 Android、JVM、甚至一个纯 Java 项目中都能正常工作。IDE 的“开箱即用”体验这是 JetBrains 的主场优势。IntelliJ IDEA 2024.2 及更高版本已经原生集成了对module.yaml的支持当你打开一个包含module.yaml的目录时IDEA 会自动识别它为一个 Amper 项目并启动相应的构建索引。src/commonMain、src/androidMain等目录会被自动标记为正确的源码根目录代码补全、跳转、重构功能全部可用。最令人惊喜的是IDEA 的 “Run Configuration” 现在可以直接选择Amper Build并让你在 UI 中勾选要构建的平台iosArm64,android,jvm而无需记忆任何命令行参数。这种深度集成是任何第三方插件都无法比拟的。4. 实操过程与核心环节实现从零开始搭建一个 Amper KMP 项目4.1 环境准备安装 Amper CLI 与验证基础依赖在动手之前请确保你的开发环境满足最低要求。这不是一个简单的npm install而是一次对整个 Kotlin 生态栈的梳理第一步确认 JDK 版本Amper 要求 JDK 17 或更高版本。运行以下命令验证java -version # 输出应为类似openjdk version 17.0.1 2021-10-19如果版本过低请从 Adoptium 下载并安装 Temurin JDK 17。切勿使用 JDK 21尽管它更新但截至 2024 年中Amper 对 JDK 21 的支持仍处于实验阶段可能会在 Kotlin/Native 编译时遇到UnsupportedClassVersionError。第二步安装 Amper CLIAmper 提供了两种安装方式推荐使用官方脚本因为它会自动处理所有依赖# macOS / Linux curl -fsSL https://amper.jetbrains.com/install.sh | sh # Windows (PowerShell) iwr -useb https://amper.jetbrains.com/install.ps1 | iex安装完成后运行amper --version验证。你应该看到类似Amper CLI v0.12.3的输出。这个 CLI 是你与 Amper 交互的唯一入口它会自动管理其内部的 Gradle、Kotlin 编译器、以及各平台 SDK 的下载和缓存。第三步初始化第一个项目进入你希望创建项目的目录执行amper init my-first-kmp-lib cd my-first-kmp-libamper init命令会创建一个最小可行的 KMP 库项目其结构如下my-first-kmp-lib/ ├── module.yaml ├── src/ │ ├── commonMain/ │ │ └── kotlin/ │ │ └── MyFirstKmpLib.kt # 一个空的 Kotlin 文件 │ └── jvmMain/ │ └── kotlin/ │ └── JvmGreeting.kt # JVM 平台的实现注意它默认只包含了jvm平台。这是因为jvm是最稳定、最无依赖的起点。接下来我们将一步步为其添加 Android 和 iOS 支持。4.2 添加 Android 支持从module.yaml到真机调试步骤一编辑module.yaml声明 Android 平台打开module.yaml将platforms数组修改为platforms: - jvm - android保存文件。此时Amper 还不知道你的项目需要一个 Android App 来消费它所以我们需要创建一个配套的 App 项目。步骤二创建 Android App 项目在my-first-kmp-lib的同级目录下运行amper init my-first-android-app --type kmp/app cd my-first-android-app--type kmp/app参数告诉 Amper这是一个跨平台应用而非一个库。它会生成一个包含android和common源码集的项目。步骤三建立模块间依赖回到my-first-android-app项目编辑其module.yaml在dependencies部分添加对my-first-kmp-lib的本地引用dependencies: # 使用 file:// 协议引用本地项目 - file:///full/path/to/my-first-kmp-lib:my-first-kmp-lib:1.0.0将/full/path/to/替换为你电脑上my-first-kmp-lib目录的绝对路径。Amper 会自动解析这个路径并在构建时将my-first-kmp-lib的jvm和android产物链接进来。步骤四编写并运行 Android App在my-first-android-app/src/androidMain/kotlin/下创建一个MainActivity.kt文件import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.example.myfirstkmp.MyFirstKmpLib class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 调用 KMP 库中的函数 val greeting MyFirstKmpLib().greet() println(Android says: $greeting) } }然后在终端中运行amper build --platform android --variant debugAmper 会自动下载并配置所需的 Android SDK如果尚未安装。编译my-first-kmp-lib的android产物。编译my-first-android-app的android产物。生成一个app-debug.apk。最后用adb install app-debug.apk将其安装到你的 Android 设备上。打开 App查看 Logcat你应该能看到Android says: Hello from Kotlin Multiplatform!的日志。恭喜你已经完成了 KMP 的“Hello World”而且全程没有碰过一行build.gradle.kts。4.3 添加 iOS 支持从module.yaml到 Xcode 集成为 iOS 添加支持比 Android 更具挑战性因为它涉及到 Xcode 工具链和 Apple 的签名体系。但 Amper 的设计让这个过程变得异常清晰。步骤一扩展my-first-kmp-lib的平台支持回到my-first-kmp-lib目录编辑module.yaml将platforms更新为platforms: - jvm - android - iosArm64 - iosSimulatorArm64保存。Amper 会立即检测到这个变更。步骤二为 iOS 创建一个 Xcode 项目Amper 不会也不能直接生成一个完整的 Xcode 项目但它会生成一个.xcframework这是 iOS 生态的标准二进制分发格式。运行amper build --platform iosArm64,iosSimulatorArm64 --variant release这个命令会为两个 iOS 平台真机和模拟器分别构建并最终将它们合并成一个my-first-kmp-lib.xcframework存放在build/xcode-frameworks/目录下。步骤三在 Xcode 中集成.xcframework打开你的 Xcode 项目可以是新建的也可以是已有的。在 Project Navigator 中右键点击你的 Target选择Add Files to YourApp...。导航到my-first-kmp-lib/build/xcode-frameworks/选中my-first-kmp-lib.xcframework勾选Copy items if needed点击Add。在Build Settings中搜索Framework Search Paths添加$(PROJECT_DIR)/my-first-kmp-lib/build/xcode-frameworks。在Build Phases-Link Binary With Libraries中确保my-first-kmp-lib.xcframework已被添加。步骤四在 Swift 代码中调用 KMP 函数在你的ViewController.swift中添加import UIKit import my_first_kmp_lib // 这是 Amper 为框架生成的 Swift 模块名 class ViewController: UIViewController { override func viewDidLoad(_ animated: Bool) { super.viewDidLoad(animated) // 调用 KMP 库 let greeting MyFirstKmpLib().greet() print(iOS says: \(greeting)) } }运行项目。如果一切顺利你将在 Xcode 的 Console 中看到iOS says: Hello from Kotlin Multiplatform!。至此你的 KMP 库已经同时在 Android 和 iOS 上跑起来了而所有的平台配置都浓缩在了两份简洁的module.yaml文件中。5. 常见问题与排查技巧实录那些官方文档不会写的“踩坑”现场5.1 “Could not resolve dependency” 错误本地路径依赖的陷阱现象当你在my-first-android-app/module.yaml中使用file://协议引用本地 KMP 库时amper build报错Could not resolve dependency file:///Users/me/dev/my-first-kmp-lib:my-first-kmp-lib:1.0.0根本原因Amper 的file://依赖解析要求被引用的项目my-first-kmp-lib必须已经成功构建过一次。它不是简单地复制文件而是去读取my-first-kmp-lib/build/publications/目录下的maven-metadata.xml和pom.xml文件。如果my-first-kmp-lib还没构建过这个目录就不存在。解决方案在my-first-android-app之前务必先构建my-first-kmp-libcd /path/to/my-first-kmp-lib amper build --platform jvm,android,iosArm64,iosSimulatorArm64 cd /path/to/my-first-android-app amper build --platform android实操心得我曾经在一个团队中推广 Amper有位同事连续三天卡在这个错误上。后来发现他是在my-first-kmp-lib目录下运行了amper build但没有指定--platform参数导致 Amper 只构建了默认的jvm平台而android和ios的 publication 目录并未生成。记住amper build必须带上你计划使用的平台列表否则 publication 就是不完整的。5.2 “Xcode build failed with exit code 65”iOS 构建失败的万能排查法现象amper build --platform iosArm64失败最终报错指向 Xcode 的exit code 65这是一个非常宽泛的错误可能由几十种原因引起。高效排查流程按优先级排序检查 Xcode 命令行工具路径xcode-select -p # 正确输出应为/Applications/Xcode.app/Contents/Developer # 如果是 /Library/Developer/CommandLineTools则说明你安装了独立的 CLT这与 Amper 不兼容 sudo xcode-select -s /Applications/Xcode.app/Contents/Developer验证 Xcode 的 Command Line Tools 版本在 Xcode 中进入Xcode Settings Locations确保Command Line Tools下拉菜单中选择的是你当前主 Xcode 的版本如Xcode 15.4而不是None或一个旧版本。清理 Amper 的构建缓存Amper 的缓存有时会损坏。删除项目根目录下的build/和.amper/目录然后重试rm -rf build/ .amper/ amper build --platform iosArm64检查 Kotlin/Native 编译器版本module.yaml中的kotlin.version必须与你安装的 Xcode 版本兼容。截至 2024 年中Xcode 15.4 推荐搭配 Kotlin 1.9.20。如果module.yaml中指定了1.9.10请升级。终极手段如果以上都不行运行amper build --platform iosArm64 --verbose它会输出完整的 Xcode 构建日志。将日志中CompileSwiftSources或LinkStoryboards附近几行的错误信息直接粘贴到 Google 搜索通常能找到具体的解决方案。5.3 “Deprecated Gradle features were used” 警告Gradle 版本的静默降级**