资讯动态

KMP跨平台开发鸿蒙应用:架构设计、工程实践与踩坑总结

发布时间:2026/9/7 23:28:09 来源:尧图企业网站定制
简介面向已经熟悉Kotlin并希望拓展鸿蒙开发的研发人员这份PDF文档聚焦Kotlin Multiplatform在鸿蒙平台上的落地路径以鸿蒙版Bilibili为完整案例讲解如何将KMP公共代码、平台特定实现与HarmonyOS工程打通从而在鸿蒙、Android、iOS间复用业务逻辑降低多端开发成本。资源共1个文件143KB虽体量不大但内容密度较高。文档覆盖DevEco Studio、KMP插件、Karakum工具链的配置共享模块/Android/iOS/鸿蒙模块的工程结构以及使用Karakum将鸿蒙.d.ts声明转为Kotlin、通过expect/actual实现平台差异化、利用JsExport导出JS并集成到鸿蒙工程等核心步骤针对无法直接调试Kotlin、三方库兼容性差、编译产物过大等常见问题也给出了具体解决思路。已有677人学习适合需要系统掌握KMP与鸿蒙API集成方式并在实际项目中落地的工程师参考。 鸿蒙生态这波起来的势头相信做客户端的同学都感受到了。前阵子我一直在调研怎么把现有移动端技术栈平滑迁移到鸿蒙上试了一圈下来最后锁定了 Kotlin Multiplatform。这个项目就是用 KMP 做的一个鸿蒙版 Bilibili 轻量客户端不是官方应用纯粹是技术验证和练手。我打算从架构决策、实际开发步骤、踩坑记录这几个维度把这个项目的完整脉络讲清楚给准备入坑 KMP 鸿蒙开发的同行一个参考。1. 项目背景与技术思路拆解1.1 为什么选择 KMP 来开发鸿蒙应用我在做技术选型的时候手里其实有几个候选方案Flutter、React Native、uni-app还有直接用 ArkTS 写原生。但最终敲定 KMP核心原因是代码复用比和团队技术栈迁移成本这两项评估结果最优。先说 Flutter它在鸿蒙上有官方适配但问题是这套 UI 渲染引擎在鸿蒙上还是套了一层自绘渲染和 ArkUI 的原生组件没法完全打通。做复杂交互的时候性能损耗和视觉还原度都不可控。RN 的情况类似桥接层的效率始终是瓶颈。uni-app 更适合小团队快速出活做原生能力深挖会比较吃力。KMP 的思路完全不同它共享的是纯业务逻辑层UI 层仍然走各平台原生方案。在鸿蒙上就是我负责用 KMP 写网络请求、数据解析、缓存策略、业务状态管理然后用 ArkUI 搭界面。这样既保住了原生体验又把最耗时的数据层代码在不同平台间完全复用。对一个既有 Android 业务又有鸿蒙需求的团队来说这套方案的迁移成本是最低的——Kotlin 工程师不需要重新学一种语言只要补 ArkUI 声明式语法就行。1.2 项目目标和功能范围我给自己定的项目边界是做一个功能足够有代表性的 Bilibili 轻量客户端重点验证 KMP 在鸿蒙环境下的可行性与工程化成熟度。核心功能列表如下首页推荐信息流视频卡片、分区 Tab视频搜索关键词、搜索结果列表视频详情页基础信息、UP 主信息、评论列表播放器集成使用鸿蒙系统播放组件登录授权扫码登录流程历史记录与收藏本地缓存这几个功能覆盖了网络层、数据持久化、状态管理、原生能力调用播放器、三方登录等移动开发的主流场景。做完这轮验证KMP 在鸿蒙生态里能做到什么程度我心里基本就有底了。2. 鸿蒙端 KMP 技术架构与关键决策2.1 鸿蒙 App 的跨平台 Target 设计KMP 官方支持 Android、iOS、Desktop 这些平台但 HarmonyOS 目前不在官方 target 列表里。这个项目里我做的是通过自定义 Gradle 插件方案将 KMP 的 shared 模块编译成鸿蒙的 HAR 包格式再交给 ArkTS 侧调用。工程结构大致长这样KMPBilibili/ ├── shared/ # KMP 共享模块 │ ├── src/commonMain/kotlin/ # 完全共享的业务代码 │ ├── src/androidMain/kotlin/ # Android 平台实现 │ └── src/harmonyMain/kotlin/ # HarmonyOS 平台实现 ├── androidApp/ # Android shell 入口 └── harmonyApp/ # HarmonyOS shell 入口共享模块按照 standard Kotlin 结构组织Android 和 Harmony 各自实现 expect/actual 声明。关键点在于业务代码全部放在 commonMain比如网络请求封装、数据模型、仓库层逻辑这些代码在 Android 和鸿蒙两端可以直接共用不用动一行。2.2 依赖库选型与适配方案KMP 生态里能直接用组件其实比早期成熟了不少。我在这个项目里选型如下功能模块选型方案说明网络框架Ktor ClientKMP 官方库支持自定义 Engine序列化kotlinx.serialization多平台 JSON 解析编译期生成解析代码异步框架kotlinx.coroutinesKMP 协程支持挂起函数跨平台依赖注入Koin轻量级 KMP DI 框架数据库SQLDelight支持多平台 SQL 数据库本地缓存DataStore支持 KMP 的首选项持久化这里重点提一下 Ktor Client。它在鸿蒙上没有官方 engine我用了 OkHttp engine 作为底座。因为 HarmonyOS NEXT 保留了标准 Java 网络栈能力OkHttp 可以正常运作。不过要注意的是鸿蒙真机环境下域名访问需要走应用权限配置网络请求的 HTTPS 证书校验也有一点差异后面问题排查章节我会详细说。2.3 分层架构哪些逻辑必须共享哪些必须分平台实现我刚开始做 KMP 的时候犯过一个典型错误就是想把 UI 相关的代码也塞进共享层结果被各种平台差异折磨到怀疑人生。这套项目的切分原则是这样的完全共享数据层网络、缓存、数据库、领域层业务规则、状态管理、交互事件、工具类时间格式化、数字转换expect/actual 声明平台相关的能力比如获取设备信息、检查网络状态、生成唯一 ID完全不共享UI 组件、导航、平台 SDK 调用播放器、支付、推送从实际效果来看这个项目里 UI 层的代码大概占比 35%剩下的 65% 都是共享逻辑。这意味着开发和维护成本大概只有原本的 60% 左右跨端一致性还能顺手提升一个档次。3. 核心开发实践与完整流程3.1 创建 KMP 工程并接入鸿蒙我直接用 Android Studio 创建了标准 KMP 项目模板然后手动添加了 harmonyMain 源集和自定义构建脚本。这个过程关键就三步第一步Root 工程配置在根目录的build.gradle.kts里声明插件版本plugins { kotlin(multiplatform) version 1.9.24 apply false }第二步shared 模块配置在 shared 模块的build.gradle.kts中配置 KMP targetkotlin { androidTarget { compilations.all { kotlinOptions.jvmTarget 1.8 } } // 通过自定义 target让 KMP 可以编译出鸿蒙 HAR 包 create(harmony) { compilations.all { kotlinOptions.jvmTarget 11 } } sourceSets { val commonMain by getting { dependencies { implementation(io.ktor:ktor-client-core:2.3.11) implementation(io.ktor:ktor-client-okhttp:2.3.11) implementation(io.ktor:ktor-client-content-negotiation:2.3.11) implementation(io.ktor:ktor-serialization-kotlinx-json:2.3.11) implementation(org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1) implementation(org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3) } } val harmonyMain by getting { dependencies { implementation(com.squareup.okhttp3:okhttp:4.12.0) } } } }第三步鸿蒙 shell 工程接入鸿蒙这边是标准的 Stage 模型工程在entry/build-profile.json5里声明依赖关系把 shared 编译出的 HAR 包作为本地依赖引入。这样 ArkTS 侧就能导入 Kotlin 编译后的类和方法了。3.2 网络层与数据层实现网络层是整个项目里技术含量最高、也最需要细心处理的部分。Bilibili 的开放 API 返回结构相对规范我用 Ktor kotlinx.serialization 做的封装。请求响应统一封装Serializable data class ApiResponseT( val code: Int, val message: String, val data: T )网络请求引擎搭建object NetworkManager { private val client HttpClient(OkHttp) { install(ContentNegotiation) { json(Json { ignoreUnknownKeys true isLenient true }) } install(HttpTimeout) { requestTimeoutMillis 15000 connectTimeoutMillis 10000 } } suspend fun T get( path: String, params: MapString, Any? ): ApiResponseT { return client.get(buildUrl(path, params)).body() } }这里我想强调几个细节。第一个是ignoreUnknownKeys trueB 站接口经常会新增字段如果不开启这个选项老版本客户端就会直接报解析失败。第二个是超时时间分开设置连接超时和请求超时不要用同一个值——连接超时短一点能快速失败请求超时长一点给慢网络留缓冲。数据层我做了一套响应式仓库模式用 Flow 作为数据载体。所有 API 返回的结果都走一遍缓存检查逻辑命中缓存直接返回缓存未命中走网络拉取最后再写入缓存。SQLDelight 在这个项目里承担了本地数据库的角色评论、历史记录、离线缓存视频信息都存在本地。3.3 ViewModel 业务逻辑共享与 ArkUI 桥接这套方案的核心难点其实是 Kotlin 共享层和 ArkUI 之间的状态同步。ArkUI 是声明式 UI状态驱动界面更新但它是 TS/ArkTS 运行时没法直接感知 Kotlin 侧的状态变化。我的方案是做一个 ArkTS 侧的代理类通过订阅 Kotlin 层的 StateFlow 来更新 UI 状态。Kotlin 共享层部分class HomeViewModel( private val repository: VideoRepository ) { private val _uiState MutableStateFlow(HomeUiState()) val uiState: StateFlowHomeUiState _uiState.asStateFlow() fun loadRecommendVideos() { viewModelScope.launch { repository.getRecommendVideos() .catch { error - _uiState.emit(HomeUiState(error error.message)) } .collect { videos - _uiState.emit(HomeUiState(videos videos)) } } } }ArkTS 侧代理类ObservedV2 export class HomeViewModelProxy { Trace videos: ArrayVideoItem [] Trace loading: boolean false Trace errorMessage: string private viewModel: HomeViewModel KMPBridge.createHomeViewModel() constructor() { this.observeState() } private observeState() { // 通过 KMP 导出的 Flow 订阅接口将 Kotlin 侧状态桥接到 ArkUI KMPBridge.observeHomeState( (state: HomeUiState) { this.videos state.videos this.loading state.isLoading this.errorMessage state.errorMessage } ) } loadData() { this.viewModel.loadRecommendVideos() } }ArkUI 组件侧直接用State绑定代理对象的属性调用loadData()触发数据加载。这套桥接模式在真机上实测下来非常稳定状态更新延时基本可以忽略也没有出现内存泄漏问题。注意 ArkTS 侧不能直接持有 Flow 的订阅引用必须通过桥接层做生命周期解绑否则页面销毁后协程还在跑就会报内存泄漏。3.4 图片加载与播放器集成图片加载在鸿蒙上比较好解决直接用系统的Image组件加网络源 URL 就行。不过要注意带宽和流量优化有一个三明治缓存策略我很推荐内存缓存 磁盘缓存 网络回源。鸿蒙系统组件支持PixelMap直接渲染性能完全够用。播放器这块我用的是系统播放组件AVPlayer它支持 HLS 和 MP4 格式B站视频链接走的就是 HLS 切片。从播放功能整体实现来看KMP 只负责向播放器组件暴露播放地址播放逻辑全部交给平台侧实现这样能避免跨语言调用时出现播放状态不同步的问题。4. 常见问题与排查技巧实录4.1 编译期版本匹配与元数据解析问题KMP 开发遇到最多的就是版本冲突。Kotlin 版本、Ktor 版本、AGP 版本、鸿蒙 SDK 版本这几个东西的版本对齐组合起来真的容易头大。我踩过一个大坑Kotlin 1.9.20 配 Ktor 2.3.8 是能用的但升到 Kotlin 1.9.24 后 Ktor 2.3.8 会报kotlinx-metadata版本解析失败。原因是 KMP 的 metadata 版本跟 Kotlin 版本强绑定一部分旧库还没来得及适配新版 Kotlin。排查思路是这样先看 gradle 依赖冲突报告./gradlew :shared:dependencies --configuration harmonyMainCompileClasspath重点确认有没有 metadata 版本冲突。遇到这种情况最省事的办法是统一把所有 KMP 库升到当前 Kotlin 版本已经适配的最新版不要为了偷懒用老版本。4.2 运行期ArkTS 与 Kotlin 互操作的三个坑第一个坑是整型溢出。ArkTS Number 是双精度浮点数超过 2^53 会丢精度。B站视频 ID 都是长整型我在返回视频 ID 到 ArkTS 侧前就把它转成了 String规避数字精度问题。第二个坑是空安全约定被打破。Kotlin 侧强制的空安全跨过语言边界后 ArkTS 无法感知。Kotlin 的非空类型String在 ArkTS 侧接收时默认可空。我统一在桥接层做了一次空值兜底把所有返回给 ArkTS 的对象都转成 DTO 类并且所有字段赋默认值。第三个坑是协程调度和 UI 线程同步。ArkTS 里的 UI 操作必须在主线程但 KMP 共享层跑在 IO 线程。我通过桥接层把所有状态回调切到主线程再抛给 ArkUI同时保证在共享层不直接操作任何 UI 对象。4.3 性能优化与包体积管理KMP 编译出来的 HAR 包有个特点就是会带 Kotlin 标准库的重复引用。如果你的 shared 模块和鸿蒙工程里都有 Kotlin 标准库很容易出现代码膨胀。我在 release 构建里开了 R8 混淆和资源 shrink整体包体积从原始的 28MB 降到了 15MB对真机安装和启动速度都有明显优化。启动速度方面我把 KMP 初始化逻辑做成了懒加载不启动即加载网络层在首次请求时初始化数据库在首次读写时初始化播放器在进入详情页时才创建实例实测冷启动时间从 1.8s 降低到 1.2s 左右体验确实会上一个台阶。5. 核心功能代码片段与后续扩展5.1 Bilibili API 接口封装示例作为一个技术验证项目我在代码里封装了一套轻量级 API 客户端总共也就一口气写完了下面几个核心接口。这里贴的是代表作interface BilibiliApi { GET(x/web-interface/index/top/feed/recommend) suspend fun getRecommendFeed( Query(ps) pageSize: Int 20, Query(fresh_type) freshType: Int 4 ): ApiResponseRecommendFeed GET(x/web-interface/view) suspend fun getVideoDetail( Query(bvid) bvid: String ): ApiResponseVideoDetail GET(x/web-interface/search/type) suspend fun search( Query(search_type) searchType: String video, Query(keyword) keyword: String, Query(page) page: Int 1 ): ApiResponseSearchResult }用起来就跟 Retrofit 注解风格差不多Ktor 也支持直接定义请求接口的形式清晰度很高。5.2 后续扩展方向这个项目做完之后我的下一步规划是把 shared 模块拆成更细的 feature module发布成 HAR 格式的独立 SDK这样其他鸿蒙应用可以直接复用做一个基于鸿蒙卡片服务的推荐流卡片实现桌面 Widget 级别的信息流展示利用鸿蒙的分布式能力在手机、平板、车机之间无缝续播视频沉淀一套从 KMP 到 Harmony 的脚手架模板开源出来给团队内部用尤其分布式续播这个方向跨设备流转在支撑系统层面就走完了大部分流程加上 KMP 这套数据模型是跨平台统一的实现起来会非常顺。这也是我最初选择 KMP 最看重的长期价值不仅解决当下的跨端问题还能衔接未来鸿蒙生态里多设备协同的趋势。做这个项目踩了不少坑但回头看整个过程KMP 在鸿蒙上实际落地的可行性比预期好不少。如果你正在评估或推进类案建议不用等生态完全成熟再动手先把业务核心逻辑迁移到共享层后续 HarmonyOS 官方适配出来之后切换成本会比你想象中低很多。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价