这是一份基于我两天内解决的一系列问题,整理出的完整KMP + 鸿蒙(OpenHarmony/HarmonyOS NEXT)混合开发环境搭建指南。
这份指南的核心架构是:业务逻辑共享(KMP),UI 分离(Compose for Android/iOS, ArkUI for HarmonyOS)。
KMP 鸿蒙化环境搭建指南
1. 核心架构设计
由于 JetBrains 官方 Compose Multiplatform 尚未正式支持鸿蒙原生渲染,我们采用 “分离架构”:
- commonMain: 存放纯 Kotlin 业务逻辑 (ViewModel, Repository, Network, Model)。鸿蒙只编译这一层。
- composeMain: 存放 Compose UI 代码 (Screen, Component, App.kt) 和 Compose 资源。鸿蒙不编译这一层,Android/iOS 编译这一层。
- openHarmonyMain: 鸿蒙特有的 Native 实现 (如果有)。
- HarmonyOS (DevEco Studio): 使用 ArkUI 编写 UI,通过 NAPI 调用 KMP 生成的
.so动态库。
2. 环境准备
- IDE:
- Android Studio (用于编写 Kotlin 逻辑和 Compose UI)。
- DevEco Studio NEXT (用于编写鸿蒙 ArkUI 和 C++ 桥接)。
- SDK:
- JDK 17+。
- OpenHarmony SDK ( API 12 +)。
- 插件:
- Android Studio 安装 Kotlin Multiplatform 插件。
3. 工程配置 (Android Studio 侧)
步骤 3.1:配置 gradle.properties
为了避免 Kotlin 默认分层模板与我们自定义的“UI/逻辑分离”结构冲突,强烈建议禁用默认模板。
# 禁止自动应用分层模板,由我们手动管理 dependsOn
kotlin.mpp.applyDefaultHierarchyTemplate=false
# 开启 Gradle 构建缓存
org.gradle.caching=true
kotlin.code.style=official
步骤 3.2:配置 libs.versions.toml
确保你有基础的 KMP 依赖,如果还没有,请添加协程等基础库。
[versions]
kotlin = "1.9.20" # 或更高
agp = "8.2.0"
compose = "1.6.0"
kotlinx-coroutines = "1.7.3"
[libraries]
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
# ... 其他依赖
步骤 3.3:配置 composeApp/build.gradle.kts
这是最关键的一步,定义 Target 和 SourceSet 依赖关系。
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 {
// --- 1. Android Target ---
androidTarget {
compilerOptions { jvmTarget.set(JvmTarget.JVM_11) }
}
// --- 2. OpenHarmony Target (核心) ---
val openHarmonyTarget = linuxArm64("openHarmony")
openHarmonyTarget.apply {
binaries {
// 生成供鸿蒙调用的动态库 (.so)
sharedLib {
baseName = "kmp_business" // 最终生成 libkmp_business.so
}
}
}
// --- 3. iOS Targets ---
iosX64()
iosArm64()
iosSimulatorArm64()
// --- 4. SourceSets 定义 ---
sourceSets {
// [纯逻辑层]:鸿蒙、Android、iOS 都能用
val commonMain by getting {
dependencies {
// 只能放纯 Kotlin 库,绝对不能放 compose.*
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
}
}
// [Compose UI 层]:只有 Android 和 iOS 能用
val composeMain by creating {
dependsOn(commonMain) // 继承逻辑层
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources) // 资源库
implementation(compose.components.uiToolingPreview)
}
}
// [Android 实现]
val androidMain by getting {
dependsOn(composeMain) // 继承 UI 层
dependencies {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
}
}
// [iOS 实现]
val iosX64Main by getting { dependsOn(composeMain) }
val iosArm64Main by getting { dependsOn(composeMain) }
val iosSimulatorArm64Main by getting { dependsOn(composeMain) }
// [鸿蒙 实现]
val openHarmonyMain by getting {
dependsOn(commonMain) // ⚠️ 只继承纯逻辑,避开 UI
}
}
}
// ... android { ... } 配置保持不变
4. 代码与资源结构调整 (物理文件移动)
为了配合上面的 Gradle 配置,你需要手动调整文件目录。
❌ 错误的结构 (会导致鸿蒙编译失败):
src/commonMain/kotlin/App.kt(包含 UI 代码)src/commonMain/composeResources/(包含图片资源)
✅ 正确的结构:
composeApp/src/
├── commonMain/ <-- 纯逻辑
│ └── kotlin/
│ └── com/example/
│ ├── ViewModel.kt
│ └── Repository.kt
│
├── composeMain/ <-- UI + 资源
│ ├── kotlin/
│ │ └── com/example/
│ │ ├── App.kt (Composable 函数)
│ │ └── Screen.kt
│ │
│ └── composeResources/ <-- 🔥 资源文件夹移到这里
│ ├── drawable/
│ │ └── logo.xml
│ └── values/
│
├── openHarmonyMain/ <-- 鸿蒙特有逻辑
└── androidMain/
操作重点:
- 把所有
@Composable代码从commonMain移到composeMain。 - 把
composeResources文件夹从commonMain移到composeMain。
5. 编译与验证
5.1 生成资源类
移动资源后,需要重新生成 Res 类:
./gradlew clean :composeApp:generateComposeResClass
5.2 修正导包
去 App.kt 中,检查 Res 类的引用。通常包名会变为:
import 你的包名.composeapp.generated.resources.Res
5.3 编译鸿蒙库
执行以下命令生成 .so 文件:
./gradlew :composeApp:linkOpenHarmonyDebugShared
产物位置:
composeApp/build/bin/openHarmony/debugShared/libkmp_business.so
composeApp/build/bin/openHarmony/debugShared/libkmp_business_api.h
6. 集成到鸿蒙工程 (DevEco Studio 侧)
- 创建 Native C++ 工程。
- 导入产物:
- 将
libkmp_business.so复制到entry/libs/arm64-v8a/。 - 将
libkmp_business_api.h复制到entry/src/main/cpp/include/。
- 将
- 配置 CMakeLists.txt:
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_library(kmp_lib SHARED IMPORTED) set_target_properties(kmp_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/arm64-v8a/libkmp_business.so) target_link_libraries(entry PUBLIC libace_napi.z.so kmp_lib) - 编写 NAPI 桥接 (
hello.cpp):- 引入
.h头文件。 - 编写 C++ 函数调用
libkmp_business_symbols()->kotlin.root...。 - 暴露给 ArkTS。
- 引入
- ArkTS 调用:
import testNapi from 'libentry.so'- 在 UI 中使用。
7. 常见问题排查 (Troubleshooting)
| 问题现象 | 原因 | 解决方案 |
|---|---|---|
| Gradle 报错: Default Kotlin Hierarchy… | 默认分层模板与自定义配置冲突 | 在 gradle.properties 添加 kotlin.mpp.applyDefaultHierarchyTemplate=false |
| Unresolved reference: Res | IDE 索引没更新 或 资源生成路径未注册 | 1. 确认资源文件夹已移至 composeMain。2. 运行 generateComposeResClass。3. 检查 App.kt 的 import 包名。 |
| Unresolved reference: Greeting | 代码分层错误 | 确保 Greeting 类在 commonMain,且 composeMain 正确 dependsOn(commonMain)。 |
| 鸿蒙编译报错: 找不到 compose 库 | openHarmonyMain 依赖了 UI 层 | 确保 openHarmonyMain 只依赖 commonMain,且 commonMain 里没有 compose 依赖。 |
按照此指南操作,你可以实现 “一套 Kotlin 业务逻辑,同时驱动 Android/iOS (Compose) 和 HarmonyOS (ArkUI)” 的终极目标。
742

被折叠的 条评论
为什么被折叠?



