一、为什么需要多平台共享代码

在现代软件开发中,跨平台需求越来越普遍。比如,你可能需要同时为 Android、iOS 和 Web 提供服务,但如果每个平台都单独开发一套业务逻辑,不仅维护成本高,而且容易产生不一致的问题。这时候,共享代码就显得尤为重要。

Kotlin 多平台(Kotlin Multiplatform, KMP)正是为了解决这个问题而生的。它允许开发者用 Kotlin 编写核心逻辑,然后编译成不同平台的目标代码,比如 JVM(Android)、Native(iOS)和 JS(Web)。而 Gradle 作为构建工具,则负责管理整个项目的依赖和编译流程。

二、Gradle 与 Kotlin 多平台项目的基本配置

要创建一个 Kotlin 多平台项目,首先需要在 build.gradle.kts 文件中进行配置。以下是一个典型的配置示例:

plugins {
    kotlin("multiplatform") version "1.9.0" // 使用 Kotlin 多平台插件
}

repositories {
    mavenCentral() // 使用 Maven 中央仓库
}

kotlin {
    // 定义目标平台
    jvm() // 编译为 JVM 字节码(Android 或后端)
    iosArm64() // 编译为 iOS ARM64 原生代码
    js(IR) { // 编译为 JavaScript
        browser() // 目标环境为浏览器
    }

    // 公共代码模块
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(kotlin("stdlib-common")) // 公共标准库
            }
        }

        // JVM 平台专用代码
        val jvmMain by getting {
            dependencies {
                implementation(kotlin("stdlib-jdk8")) // JVM 标准库
            }
        }

        // iOS 平台专用代码
        val iosMain by getting {
            dependencies {
                // iOS 平台可能需要的额外依赖
            }
        }

        // JS 平台专用代码
        val jsMain by getting {
            dependencies {
                implementation(kotlin("stdlib-js")) // JS 标准库
            }
        }
    }
}

代码说明:

  1. kotlin("multiplatform") 是 Kotlin 多平台插件的声明。
  2. jvm()iosArm64()js() 分别定义了三个目标平台。
  3. sourceSets 定义了不同平台的代码模块,commonMain 是公共代码,其他则是平台专用代码。

三、如何编写共享代码

共享代码的核心在于 commonMain 模块。我们可以在这里定义接口、数据模型和业务逻辑,然后在不同平台实现具体细节。

示例:定义一个跨平台的网络请求工具

// commonMain 模块
expect class HttpClient() { // expect 声明,表示各平台需要实现
    fun get(url: String): String
}

// jvmMain 模块(Android 或 JVM 后端)
actual class HttpClient actual constructor() {
    actual fun get(url: String): String {
        // 使用 Java 标准库实现 HTTP 请求
        return java.net.URL(url).readText()
    }
}

// iosMain 模块(iOS)
actual class HttpClient actual constructor() {
    actual fun get(url: String): String {
        // 使用 iOS 的 NSURLSession 实现(这里用伪代码表示)
        return "iOS HTTP Response"
    }
}

// jsMain 模块(Web)
actual class HttpClient actual constructor() {
    actual fun get(url: String): String {
        // 使用 JavaScript 的 Fetch API
        return "JS HTTP Response"
    }
}

代码说明:

  1. expect 关键字声明了一个“预期”的类或方法,表示各平台需要实现它。
  2. actual 关键字用于提供平台特定的实现。
  3. 这样,我们在 commonMain 中调用 HttpClient().get() 时,不同平台会自动使用自己的实现。

四、构建与发布多平台产物

配置完成后,我们可以使用 Gradle 命令编译不同平台的代码:

./gradlew assemble # 编译所有平台
./gradlew jvmJar # 仅编译 JVM 平台
./gradlew iosArm64Binaries # 仅编译 iOS 平台
./gradlew jsBrowserProductionWebpack # 编译 JS 并打包

注意事项:

  1. iOS 编译需要 macOS 环境(因为依赖 Xcode 工具链)。
  2. JS 编译会生成可部署的静态文件,适合 Web 应用。
  3. 可以使用 publishing 插件将库发布到 Maven 仓库,供其他项目使用。

五、技术优缺点分析

优点:

  1. 代码复用率高:核心逻辑只需写一次,减少重复劳动。
  2. 维护成本低:修改公共代码后,所有平台同步更新。
  3. 性能接近原生:Kotlin/Native 编译的 iOS 代码运行效率高。

缺点:

  1. 学习曲线较陡:需要熟悉 Kotlin 多平台的特性和 Gradle 配置。
  2. 调试复杂:不同平台的调试方式不同,尤其是 iOS 需要额外工具。
  3. 生态仍在发展:某些库可能没有多平台支持,需要自己封装。

六、适用场景

  1. 跨平台移动应用:比如用 Compose Multiplatform 开发 Android 和 iOS 应用。
  2. 前后端共享逻辑:比如用 Kotlin 编写后端和 Web 前端的验证逻辑。
  3. 嵌入式与桌面应用:Kotlin/Native 支持 Linux、Windows 和 macOS。

七、总结

Kotlin 多平台 + Gradle 的组合为跨平台开发提供了强大的支持。虽然有一定的学习成本,但一旦掌握,可以大幅提升开发效率。如果你的项目需要覆盖多个平台,不妨尝试这种方案。