如何在Kotlin Compose Multi Platform中添加macOS专属代码与配置?
在KMM项目中添加macOS专属代码的配置指南
问题描述
我需要编写macOS专属代码(比如蓝牙权限这类需要Objective-C/Swift实现的底层功能),当前通过项目向导创建的KMM项目目录结构只有:
- commonMain
- androidMain
- desktopMain
请问:
- 如何创建macOS专属的main文件夹并编写代码?能否自行创建该目录?
- 需要对Gradle进行哪些正确配置?
当前我的Gradle配置文件如下:
import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidApplication) alias(libs.plugins.composeMultiplatform) alias(libs.plugins.composeCompiler) } kotlin { androidTarget { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } } jvm("desktop") macosArm64() applyDefaultHierarchyTemplate() sourceSets { val desktopMain by getting androidMain.dependencies { implementation(compose.preview) implementation(libs.androidx.activity.compose) } commonMain.dependencies { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) implementation(compose.ui) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(libs.androidx.lifecycle.viewmodel) implementation(libs.androidx.lifecycle.runtime.compose) } desktopMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutines.swing) } val jvmAndMacos by creating { dependsOn(commonMain.get()) } macosArm64Main.get().dependsOn(jvmAndMacos) jvmMain.get().dependsOn(jvmAndMacos) } } android { namespace = "com.shekhar.multiplatformapp" compileSdk = libs.versions.android.compileSdk.get().toInt() defaultConfig { applicationId = "com.shekhar.multiplatformapp" minSdk = libs.versions.android.minSdk.get().toInt() targetSdk = libs.versions.android.targetSdk.get().toInt() versionCode = 1 versionName = "1.0" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } buildTypes { getByName("release") { isMinifyEnabled = false } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } dependencies { debugImplementation(compose.uiTooling) } compose.desktop { application { mainClass = "com.shekhar.multiplatformapp.MainKt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "com.shekhar.multiplatformapp" packageVersion = "1.0.0" } } }
解决方案
1. 创建macOS专属源码目录
可以自行创建macOS对应的源码目录,目录结构要和Gradle的sourceSet对应:
- 针对Apple Silicon(M系列)芯片:
src/macosArm64Main/kotlin(放Kotlin代码)、src/macosArm64Main/swift(放Swift/Objective-C代码) - 针对Intel芯片:
src/macosX64Main/kotlin、src/macosX64Main/swift - 可选:创建
src/macosMain/kotlin作为通用macOS源码目录,让两种架构共享代码(需要在Gradle中配置关联)
2. Gradle配置调整
步骤1:添加需要的macOS架构
在kotlin块中,确保声明了需要支持的macOS架构,比如同时兼容Arm64和Intel:
kotlin { // ... 保留现有androidTarget、jvm("desktop")配置 macosArm64() macosX64() // 加上这行支持Intel芯片 applyDefaultHierarchyTemplate() }
步骤2:配置sourceSets关联
在sourceSets块中,为macOS的代码目录添加依赖和专属配置:
sourceSets { // ... 保留现有androidMain、commonMain、desktopMain配置 // 配置通用macOS sourceSet(可选,让两个架构共享代码) val macosMain by creating { dependsOn(commonMain.get()) } // 配置Arm64专属代码 val macosArm64Main by getting { dependsOn(macosMain) dependencies { implementation(libs.kotlinx.coroutines.core) // 添加macOS专属依赖 } } // 配置X64专属代码 val macosX64Main by getting { dependsOn(macosMain) dependencies { implementation(libs.kotlinx.coroutines.core) } } }
步骤3:配置Compose Desktop的macOS分发
如果用了Compose Multiplatform,当前配置里的TargetFormat.Dmg已经支持macOS安装包,还可以添加专属配置比如图标:
compose.desktop { application { mainClass = "com.shekhar.multiplatformapp.MainKt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "com.shekhar.multiplatformapp" packageVersion = "1.0.0" // macOS专属配置示例 macOS { // iconFile.set(file("src/macosMain/resources/app-icon.icns")) // 可选设置应用图标 } } } }
步骤4:Swift/Objective-C代码调用
直接在对应的swift目录下创建.swift或.m文件,Kotlin可以通过Kotlin/Native interop直接调用:
比如创建src/macosArm64Main/swift/BluetoothPermission.swift:
import CoreBluetooth func requestBluetoothPermission() { let centralManager = CBCentralManager(delegate: nil, queue: nil) centralManager.scanForPeripherals(withServices: nil) }
然后在macOS的Kotlin代码中调用:
// macosArm64Main中的Kotlin代码 external fun requestBluetoothPermission() fun checkBluetoothPermission() { requestBluetoothPermission() }
3. 修改后的完整Gradle配置
import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidApplication) alias(libs.plugins.composeMultiplatform) alias(libs.plugins.composeCompiler) } kotlin { androidTarget { @OptIn(ExperimentalKotlinGradlePluginApi::class) compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } } jvm("desktop") macosArm64() macosX64() // 添加Intel芯片支持 applyDefaultHierarchyTemplate() sourceSets { val desktopMain by getting val macosArm64Main by getting val macosX64Main by getting // 通用macOS sourceSet,可选 val macosMain by creating { dependsOn(commonMain.get()) } macosArm64Main.dependsOn(macosMain) macosX64Main.dependsOn(macosMain) androidMain.dependencies { implementation(compose.preview) implementation(libs.androidx.activity.compose) } commonMain.dependencies { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) implementation(compose.ui) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(libs.androidx.lifecycle.viewmodel) implementation(libs.androidx.lifecycle.runtime.compose) } desktopMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutines.swing) } macosArm64Main.dependencies { implementation(libs.kotlinx.coroutines.core) } macosX64Main.dependencies { implementation(libs.kotlinx.coroutines.core) } } } android { namespace = "com.shekhar.multiplatformapp" compileSdk = libs.versions.android.compileSdk.get().toInt() defaultConfig { applicationId = "com.shekhar.multiplatformapp" minSdk = libs.versions.android.minSdk.get().toInt() targetSdk = libs.versions.android.targetSdk.get().toInt() versionCode = 1 versionName = "1.0" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } buildTypes { getByName("release") { isMinifyEnabled = false } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } dependencies { debugImplementation(compose.uiTooling) } compose.desktop { application { mainClass = "com.shekhar.multiplatformapp.MainKt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "com.shekhar.multiplatformapp" packageVersion = "1.0.0" // macOS专属配置示例 macOS { // 可选:设置应用图标 // iconFile.set(file("src/macosMain/resources/app-icon.icns")) } } } }
内容的提问来源于stack exchange,提问作者shekarShinde
相关产品推荐
相关产品推荐

