Kotlin Multiplatform 和 Compose Multiplatform 开发完整指南

Viewed 0

一、KMP 和 Compose Multiplatform

在移动应用开发领域,Kotlin Multiplatform Mobile (KMM) 和 Compose Multiplatform 的结合正在成为一种强大的解决方案。它们不仅解决了传统跨平台开发中的诸多痛点,还提供了许多独特的优势,使得开发者能够更加高效地构建和维护跨平台应用。

KMM 和 Compose Multiplatform 的主要优势包括代码复用、性能优化、平台特性和灵活性、一致的开发体验以及现代化的 UI 构建。代码复用方面,它们允许开发者在 Android 和 iOS 之间共享大部分代码,包括业务逻辑和 UI 组件。性能上,与某些其他跨平台框架不同,KMM 生成的代码直接运行在目标平台的原生环境中,这意味着开发者可以享受到与原生开发相同的性能和系统级优化。

平台特性和灵活性通过 expect 和 actual 关键字实现,允许开发者为不同的平台编写特定的实现,从而充分利用各个平台的特性而不会妥协于跨平台的限制。Compose Multiplatform 同样支持这种灵活性,确保 UI 设计可以根据平台的需求进行优化。一致的开发体验源于 Kotlin 作为一种现代语言,拥有简洁的语法和强大的功能特性,深受开发者喜爱。利用 Kotlin 和 Compose Multiplatform,开发者能够在相同的开发环境中进行多平台开发,提升了开发者的体验和生产力。使用 Android Studio 和 Xcode 无缝集成,开发者可以在熟悉的 IDE 中进行跨平台开发和调试。

现代化的 UI 构建基于声明式编程范式,简化了复杂的 UI 构建。开发者可以通过简明的代码定义动态界面,减少了样板代码和 UI 更新的复杂度。这种现代化的 UI 构建方式,不仅使代码更加清晰和易于维护,还提升了开发效率。使用 KMM 和 Compose Multiplatform,开发团队可以在保证高性能和平台特性的同时,实现代码的最大复用和开发效率的提升。这种结合不仅为项目带来了显著的优势,还为开发者提供了创新和灵活的开发体验。

1. 基础概念

什么是 Kotlin Multiplatform (KMP)?
Kotlin Multiplatform (KMP) 是 JetBrains 提供的一项功能,允许使用 Kotlin 编写可以在多个平台上运行的代码。KMP 的目标是通过共享业务逻辑代码来减少不同平台开发的重复工作。KMP 支持的平台包括但不限于 JVM(用于服务器端开发以及 Android 开发)、JavaScript(用于前端 Web 开发)以及原生平台如 iOS、Windows、macOS、Linux 等。

什么是 Kotlin Multiplatform Mobile (KMM)?
Kotlin Multiplatform Mobile (KMM) 是专注于移动平台的一种 KMP 实现。KMM 让开发者能够使用 Kotlin 编写可以在 Android 和 iOS 上运行的共享代码,主要关注点是在移动设备上的应用开发。简单来说,KMM 是 KMP 的一个子集或特化实现,专注于移动开发。

什么是 Compose Multiplatform?
Compose Multiplatform 是 JetBrains 开发的一种跨平台用户界面 (UI) 框架,它基于 Kotlin 和 Jetpack Compose 的设计理念,旨在通过声明式编程范式简化跨平台 UI 构建。

什么是 Kotlin/Native、Kotlin/JVM、Kotlin/JS?与 KMP 的关系?
Kotlin 是一种现代化的编程语言,由 JetBrains 开发,支持多平台开发,包括 JVM、JavaScript 和原生平台。为了更高效地开发跨平台应用,Kotlin 提供了三种主要的编译器后端:Kotlin/JVM、Kotlin/JS 和 Kotlin/Native。Kotlin/JVM 是最初的 Kotlin 编译器后端,也是最常用的一种,它将 Kotlin 代码编译成可以在 Java 虚拟机 (JVM) 上运行的字节码,由于 Kotlin 与 Java 高度互操作,Kotlin/JVM 可以直接利用现有的 Java 库和框架,使得开发者能够轻松地将 Kotlin 与 Java 项目集成,使用场景包括 Android 开发与服务器开发。Kotlin/JS 将 Kotlin 编译为 JavaScript 代码,从而可以在浏览器或 Node.js 环境中运行,使得前端开发者可以使用 Kotlin 编写网页应用,同时充分利用现有的 JavaScript 库和框架,使用场景是 Web 前端开发。Kotlin/Native 将 Kotlin 编译为原生二进制代码,可以直接运行在不依赖 JVM 或 JavaScript 引擎的环境中,支持多种平台,包括 iOS、Windows、macOS、Linux、嵌入式设备等,甚至于 Android、鸿蒙也可以使用 KN 跨平台开发(需要编写 JNI 或 NAPI 桥接代码)。KMP 结合了 Kotlin/JVM、Kotlin/JS 和 Kotlin/Native 的优势,使开发者能够在统一的代码库中,针对不同平台进行开发,实现跨平台方案。

2. KMP 核心原理

2.1 特定于平台的 API 和实现

KMM 里的 expect/actual 机制是非常重要的,因为它提供了一种语法技术来解决平台相关的问题。举例来说,当我们需要在业务逻辑中使用设备的 model 号时,我们需要编写特定平台的代码才能实现。这时,expect 就相当于声明一个协议,它定义了我们期望得到的接口或数据,之后各个平台都需要独立地实现这个协议来满足业务需要。这种方式只需要建设一次,就像一些基础库一样只需要做一次就能在后面被大家共用,这种共用甚至不限于公司界,整个业界都可以共用一组基础库。

基本流程如下:在 commonMain 目录下建立一个 expect 类或 Top-Level 方法,类似创建一个协议声明。分别在 androidMain 和 iosMain 目录中,创建与 expect 声明完全一致的实现,否则编译器会报错。

平台抽象接口设计通常定义一个跨平台共享的接口规范,声明所有平台必须实现的属性和方法,用于保障代码在跨平台调用时的行为一致性。例如,可以定义一个 Platform 接口,包含 name 属性,用于获取当前运行平台的名称如“Android”或“iOS”。通过 expect 关键字声明一个需由各平台具体实现的公共函数,遵循 Kotlin Multiplatform 的 expect/actual 机制,调用此函数将返回实现了 Platform 接口的平台专属对象,实现编译时多态。

平台专属实现示例中,Android 端在 androidMain 中通过 actual 关键字对应 expect 声明的具体实现,编译时根据目标平台自动匹配,通过 Android SDK 获取系统版本号,增强平台特性识别能力。iOS 端在 iosMain 中同样使用 actual 关键字,调用 iOS 原生 API 如 UIDevice 获取设备信息,体现平台特定代码隔离原则。核心设计模式采用分层架构,将平台无关逻辑置于 commonMain,平台相关实现隔离在 androidMain 或 iosMain 等目录,通过接口抽象和 expect/actual 机制,实现业务逻辑与平台特性的解耦,提升代码复用率。该设计是 Kotlin Multiplatform 项目的典型结构,通过标准化的接口与平台适配层,支撑跨平台应用的统一功能开发。

2.2 直接访问 iOS Framework 的核心原理

KMM 项目中 iosMain 能直接访问 iOS Framework 的核心原理,主要依赖以下三层技术机制:跨平台代码分层机制、CInterop 原生接口绑定和编译期代码转换。

跨平台代码分层机制通过 expect/actual 声明与实现分离,实现接口统一声明、平台独立实现的架构。CInterop 原生接口绑定中,Kotlin/Native 通过 cinterop 工具生成 Objective-C/Swift 绑定的中间层,扫描 iOS Framework 的 .h 头文件,自动生成 Kotlin 可调用的 klib 接口文件包含类或方法映射。Swift 兼容处理需要方法添加 @objc 修饰符,确保可被 Objective-C 运行时识别。编译期代码转换阶段,Kotlin/Native 编译器将代码转换为 iOS 可识别的二进制格式,iosMain 代码会被编译为 Mach-O 格式的 Framework 或静态库,自动嵌入 Kotlin/Native 运行时以支持跨平台特性。产物集成输出 .framework 文件,包含编译后的二进制代码、自动生成的 Objective-C 头文件和资源文件,Xcode 工程直接依赖该 Framework 即可调用。

整体交互流程从 Kotlin Common 通过 expect 声明到 iosMain,再通过 cinterop 绑定到 iOS Framework,编译为 Mach-O 后集成到 Xcode 工程,最终动态链接到 UIKit 等系统框架。技术优势对比显示,KMM 实现方式在 API 调用方式上直接访问原生 Framework,无额外运行时开销,逻辑层代码复用率 100%,UI 层独立,而传统跨平台方案常通过桥接层间接调用,有解释器或 JIT 损耗,且全栈强制统一。这一设计使得 KMM 在保持原生性能的同时,实现了逻辑代码的跨平台复用。

2.3 cinterop 生成中间层时机

Kotlin/Native 的 cinterop 工具生成 Objective-C/Swift 绑定的中间层,其生成时机和触发条件如下:生成时机主要是编译期动态生成,绑定文件不会在新建项目时自动生成,而是在首次执行构建任务如运行 ./gradlew build 时触发生成流程,每次修改 .def 配置文件或原生头文件后,重新构建时会增量更新绑定文件。条件触发机制是仅当项目中声明了 cinterop 依赖且配置了原生框架调用时才会生成,例如在 build.gradle.kts 中配置 iosX64 平台并创建 cinterop 任务指向 UIKit.def 文件,此时才会生成对应的 klib 和头文件。

生成路径与产物包括初始生成在 build/bin/native/cinterop/ 目录下的 .klib Kotlin 库,编译后集成在 build/bin/iosX64/debugFramework/ 目录下的 .framework 二进制文件,以及头文件映射在 build/generated/cinterop/ 目录下的 .h Objective-C 头文件。生成流程对比显示,新建空项目时绑定文件未生成,需手动配置 cinterop;配置原生依赖后,在构建目录执行 Gradle 构建任务会生成绑定文件;更新头文件或配置后,重新编译会增量更新。

技术实现原理基于构建管道集成,cinterop 作为 Kotlin/Native 编译管道的前置步骤,通过 Gradle 插件与构建系统深度集成,从 Gradle Task 触发 cinterop 解析 .def 文件,生成 .klib 和 .h,再进入 Kotlin/Native 编译。动态适配机制是当检测到 src/nativeInterop/cinterop 目录下的 .def 配置文件时,自动注册生成任务。总结来说,绑定文件非预生成,需通过构建任务触发;按需生成,仅在声明特定平台如 iosMain 且配置原生依赖时生成;持续更新,头文件或配置变更后,通过重新编译实现动态更新。

二、KMM 环境搭建

1. KDoctor

kdoctor 是一个用于验证 Kotlin Multiplatform Mobile (KMM) 开发环境是否正确配置的命令行工具。它会检查系统上的各种依赖和配置,确保已经安装并正确配置了所有必要的软件,例如 Android Studio、Xcode、CocoaPods 等。如果是第一次设置 KMM 环境,强烈建议使用 kdoctor 来确认一切都已正确配置。

安装 kdoctor 对于 macOS 系统,确保 Homebrew 已安装,然后通过命令 brew install kdoctor 进行安装。使用 kdoctor 进行环境检查时,安装完 kdoctor 后,通过命令 kdoctor 检查 KMM 开发环境,kdoctor 将检查 JDK 是否安装了 Java Development Kit、Android Studio 是否安装了 Android Studio 和必要的组件、Xcode 是否安装了 Xcode 和命令行工具、CocoaPods 是否安装了 CocoaPods 用于管理 iOS 依赖。运行 kdoctor 后的示例输出可能显示所有必要的软件都已正确安装,已准备好进行 KMM 开发。如果 kdoctor 报告某些组件未正确安装或配置,按照指导信息进行相应的操作来解决问题。

2. Kotlin Multiplatform Plugin

在 Android Studio 中安装 Kotlin Multiplatform 插件:打开 Android Studio,进入 Settings -> Plugins,搜索并安装 Kotlin Multiplatform 插件,重启 Android Studio 以激活插件。

三、项目构建和解析

1. 新建 KMM 项目

打开 Android Studio,选择 New Project。在项目模板中,选择 Kotlin Multiplatform App。配置项目名称、保存路径和包名。

2. 项目架构和配置

生成的 KMM 项目包含 Android 和 iOS 两个平台的代码,以及一个共享代码模块。项目结构包括 .gradle 文件夹是 Gradle 构建工具在运行过程中生成的缓存和临时文件目录,主要用于加速构建流程和管理项目依赖;.idea 目录是 IDE 配置和元数据,Android Studio 基于 IntelliJ IDEA 开发,所有项目在首次打开时都会自动生成 .idea 目录,用于加载和存储配置;android 是移动安卓壳工程;gradle 是 gradle 环境管理,包含 gradle-wrapper.jar 是 Gradle 环境启动器,实现版本自动化管理,负责根据 gradle-wrapper.properties 中定义的版本自动下载并安装指定版本的 Gradle,gradle-wrapper.properties 定义所需的 Gradle 版本和下载源,保障跨环境一致性;ios 是移动 iOS 壳工程;shared 是共享代码模块,目前仅包含业务逻辑,还可以添加 UI 组件、资源等;.gitignore 是 Git 版本控制系统中一个纯文本配置文件,用于指定 Git 仓库中需要永久忽略跟踪的文件或目录,核心作用是过滤无需纳入版本控制的文件如临时文件、编译产物、本地环境配置等,避免这些文件被意外提交到仓库中;build.gradle.kts 是 KMM 项目中 Gradle 构建工具的核心配置文件,用于定义项目的构建规则、依赖关系和插件设置;gradle.properties 是 Gradle 构建工具的核心配置文件,用于定义全局属性、控制构建行为以及优化构建性能;.gradlew 和 .gradlew.bat 是 Gradle Wrapper 的启动脚本,用于统一项目的构建环境,确保开发者无需预先安装特定版本的 Gradle,也能正确构建项目;local.properties 存储本地敏感配置禁止提交到版本控制;settings.gradle.kts 是 Gradle 构建系统的核心配置文件,主要负责定义项目结构、管理子模块和配置构建行为。

四、配置文件详解

1. build.gradle

在 KMM 项目中,build.gradle 文件是 Gradle 构建工具的核心配置文件,用于定义项目的构建规则、模块级依赖关系和插件设置、任务等构建逻辑,属于代码的一部分。具体作用包括定义构建逻辑和依赖关系。

build.gradle 的作用是 Gradle 使用该文件来配置项目级设置如定义整个项目的构建规则、公共插件、仓库和依赖版本;模块级设置如针对每个子模块配置构建规则;多平台支持如声明 Kotlin Multiplatform 的目标平台如 Android、iOS、JVM 等;依赖管理如声明项目所需的库如 Kotlin 标准库、第三方库。

KMM 项目的典型结构通常包含以下 build.gradle 文件:项目根目录的 build.gradle 用于全局配置,定义构建工具以及所有子模块共享的规则,示例中包括 buildscript 块定义全局使用的 Gradle 插件版本如 Android 插件和 Kotlin 插件,allprojects 块配置所有子模块共享的仓库地址如 google() 和 mavenCentral(),以及根项目自身的 repositories 块;共享模块的 build.gradle 配置跨平台代码的构建规则如 Android 和 iOS 的共享逻辑,示例中通过 plugins 块应用 org.jetbrains.kotlin.multiplatform 插件,kotlin 块定义目标平台如 android() 和 iosArm64() 并配置 binaries.framework 生成 iOS 框架,android 块配置 Android 特定设置如 compileSdkVersion,dependencies 块声明公共依赖和平台专属依赖;Android App 模块的 build.gradle 配置 Android 应用的构建规则,示例中通过 plugins 块应用 com.android.application 和 kotlin-android 插件,android 块配置 compileSdk 和 defaultConfig,dependencies 块依赖共享模块和其他 Android 库;iOS 模块通常通过共享模块生成的框架集成到 Xcode 项目,无需单独的 build.gradle。

关键配置解析包括多平台目标声明通过 kotlin 块定义支持的平台如 android()、iosArm64()、iosSimulatorArm64()、jvm();依赖分类支持按平台细分依赖,如 commonMain.dependencies 用于公共依赖,androidMain.dependencies 和 iosMain.dependencies 用于平台专属依赖;iOS 框架生成配置共享模块生成 iOS 可用的框架,通过 binaries.framework 设置 baseName 和导出其他模块;定义插件通过 plugins 块应用所需插件如 com.android.application 和 kotlin-android。

常见问题与解决包括依赖解析失败时检查仓库是否包含 google() 和 mavenCentral(),确保网络可以访问仓库;插件版本冲突时统一 Kotlin 插件版本;iOS 构建失败时运行 ./gradlew :shared:packForXcode 重新生成框架,或在 Xcode 中清理构建缓存。总结来说,build.gradle 在 KMM 项目中是构建流程的核心控制器,负责定义多平台目标和编译规则、管理跨平台依赖、集成 Android 和 iOS 的构建配置、生成 iOS 框架供 Xcode 使用,通过合理配置可以实现一套代码在 Android 和 iOS 之间的高效共享,同时保持平台特定逻辑的灵活性。

2. gradle.properties

在 KMM 项目中,gradle.properties 文件是 Gradle 构建工具的核心配置文件,用于定义全局属性、控制构建环境、优化构建性能。具体作用包括配置 Gradle 构建环境,如通过设置 org.gradle.jvmargs 增加 Gradle 堆内存,启用构建缓存通过 org.gradle.caching=true,并行执行任务通过 org.gradle.parallel=true,多项目构建优化通过 org.gradle.configureondemand=true;定义项目全局变量,如在 gradle.properties 中定义公共版本号如 kotlin_version=1.8.21,在 build.gradle.kts 中引用这些变量统一管理版本号和通用配置;控制 KMM 多平台构建行为,如配置 Kotlin/Native 编译参数如 kotlin.native.binary.memoryModel=strict,禁用 iOS 模拟器 arm64 目标解决兼容性问题;管理 Android 和 iOS 构建配置,如启用 Android Jetpack Compose 通过 android.enableCompose=true,指定 Xcode 兼容版本;配置代理和仓库镜像解决国内依赖下载慢的问题,如使用阿里云镜像加速;启用实验性功能,如启用 Kotlin 新内存管理器或 Jetpack Compose Multiplatform。

文件位置与优先级包括项目级 gradle.properties 仅影响当前项目,全局级 gradle.properties 影响所有 Gradle 项目。KMM 项目典型配置示例可能包括 Gradle 配置如 org.gradle.jvmargs=-Xmx4096m,Kotlin 版本 kotlin_version=1.8.21,Android 配置 android.useAndroidX=true,KMM/Native 配置 kotlin.native.binary.memoryModel=strict,以及国内镜像加速设置。注意事项包括键值对格式必须使用 key=value 格式且不能有多余的空格,所有值均为字符串需在 build.gradle.kts 中按需转换类型,部分属性需与 Kotlin 版本匹配否则构建会失败。通过合理配置 gradle.properties,可以显著提升 KMM 项目的构建性能和跨平台开发体验。

3. local.properties

local.properties 是本地开发环境专属的配置文件,主要用于存储与开发者机器强相关的路径、密钥等敏感信息,避免将这些内容暴露在版本控制中。核心作用包括配置本地开发环境路径,如定义 Android SDK、NDK 的本地路径,用于 Gradle 构建时自动识别 Android 开发环境依赖;存储敏感信息如本地调试密钥路径及密码、私有 API 密钥或其他环境变量;隔离团队协作差异,避免因开发者本地环境差异导致构建失败,文件默认不提交至 Git 等版本控制系统。

典型配置内容可能包括 sdk.dir 指定 Android SDK 安装路径,ndk.dir 指定 NDK 路径,debug.keystore 指定本地调试 APK 的签名文件路径,custom.api.key 自定义 API 密钥。在 KMM 项目中的使用方式包括在 build.gradle 中通过代码读取配置,如创建 Properties 对象加载 local.properties 文件,然后在 android 块中引用这些属性设置签名配置;动态注入环境变量通过 Gradle 参数传递 local.properties 中的值到代码中,如在 defaultConfig 中定义 buildConfigField,然后在代码中通过 BuildConfig 访问。

最佳实践包括禁止提交至版本控制,将 local.properties 加入 .gitignore;提供模板文件如 local.properties.template 指导团队成员复制后填写本地路径;统一环境管理通过文档说明配置项含义及填写规范。与 gradle.properties 的区别在于 local.properties 仅本地环境生效,典型内容为 SDK 路径、密钥等敏感信息,不共享;而 gradle.properties 全局项目生效,典型内容为 JVM 内存、构建缓存开关、插件版本,共享。总结来说,local.properties 是 KMM 项目中用于隔离本地环境差异的核心文件,通过存储敏感信息和机器特定路径,确保团队协作时构建流程的稳定性和安全性。

4. settings.gradle

在 KMM 项目中,settings.gradle 是 Gradle 构建系统的核心配置文件,主要负责定义项目结构、管理子模块和配置构建行为。核心作用包括声明项目包含的模块,通过 include 函数明确项目中包含哪些子模块如共享代码模块、Android/iOS 平台模块,在 KMM 中通常将跨平台逻辑放在 shared 模块,并通过 include 声明其与平台模块的关联;定义模块路径,若模块不在默认路径下,需通过 project 函数指定路径;配置插件和仓库,在 KMM 中需统一 Kotlin 插件版本以兼容多平台构建,通过 pluginManagement 块指定 Kotlin 和 Android 插件版本;管理依赖解析策略,声明全局仓库地址如 Maven Central、Google 仓库,确保所有模块使用相同的依赖源。

KMM 项目中的特殊作用包括多平台模块协调,确保共享模块与平台模块的依赖关系正确传递;构建环境隔离,通过插件管理避免不同平台的构建冲突。总结来说,settings.gradle 在 KMM 项目中是多模块和多平台构建的基石,通过声明模块、管理路径和统一配置,确保跨平台代码与原生模块的高效整合,其配置直接影响 Gradle 如何识别和组织项目结构,是跨平台开发的关键文件之一。

5. gradlew

在新建 KMM 项目时,生成的 .gradlew 和 .gradlew.bat 文件是 Gradle Wrapper 的启动脚本,它们的作用是统一项目的构建环境,确保开发者无需预先安装特定版本的 Gradle,也能正确构建项目。Gradle Wrapper 的核心作用包括环境一致性,无论开发者本地安装的 Gradle 版本是什么,项目都通过 Wrapper 使用 gradle-wrapper.properties 中指定的 Gradle 版本进行构建,避免版本冲突;零配置运行,新克隆项目的开发者无需手动安装 Gradle,直接运行 Wrapper 脚本即可自动下载并配置正确的 Gradle 版本。

文件的作用包括 .gradlew 用于 Unix/Linux/macOS 平台,是 Shell 脚本用于执行 Gradle 命令如 ./gradlew build;.gradlew.bat 用于 Windows 平台,是批处理脚本功能同上;gradle/wrapper/ 目录包含 Wrapper 的核心文件如 gradle-wrapper.jar 和 gradle-wrapper.properties。核心文件解析中,gradle-wrapper.properties 定义了 Gradle 的下载地址和版本,如 distributionType 指定发行版类型通常是 bin 或 all,distributionUrl 指定 Gradle 版本必须与项目兼容;gradle-wrapper.jar 是 Wrapper 的核心实现,负责下载并安装指定版本的 Gradle。

使用 Wrapper 脚本时,在 Unix/Linux/macOS 中运行 ./gradlew build 执行构建命令,./gradlew clean 清理构建缓存,./gradlew wrapper --gradle-version=8.5 更新 Gradle 版本;在 Windows 中运行 gradlew.bat build 和 gradlew.bat clean。需要提交这些文件到版本控制以确保一致性,所有开发者使用相同的 Gradle 版本和配置,并简化协作,新成员无需手动安装或配置 Gradle。

常见问题包括 .gradlew 权限被拒绝时通过 chmod +x gradlew 赋予执行权限;更新 Gradle 版本时修改 gradle-wrapper.properties 中的 distributionUrl 并运行 Wrapper 任务下载新版本;.gradlew 文件被误删时重新生成 Wrapper。

0 Answers