# kmp-cmp-harmony **Repository Path**: licq_workspace/kmp-cmp-native ## Basic Information - **Project Name**: kmp-cmp-harmony - **Description**: 一套 Kotlin 代码跑通 Android / iOS / 鸿蒙 NEXT:KMP + Compose Multiplatform 鸿蒙统一渲染(华为 CPF 工具链)真实落地,原生壳 + CMP 混排架构,三端统一视频播放器,附完整踩坑复盘文档。 - **Primary Language**: Kotlin - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-09-10 - **Last Updated**: 2026-09-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
# KMP · CMP · 三端同源 **一套 Kotlin 代码,Android / iOS / 鸿蒙 NEXT 三端原生体验** One Kotlin codebase, three platforms: Android, iOS & HarmonyOS NEXT. [![Platform](https://img.shields.io/badge/platform-Android%20%7C%20iOS%20%7C%20HarmonyOS%20NEXT-0969DA)](#-三端架构原生壳--cmp-内容) [![Kotlin](https://img.shields.io/badge/Kotlin-2.2.21%20CPF(CN%20Harmony%20Toolchain)-7F52FF)](#-技术栈) [![CMP](https://img.shields.io/badge/Compose%20Multiplatform-1.9.2-4285F4)](#-技术栈) [![Arch](https://img.shields.io/badge/arch-%E5%8E%9F%E7%94%9F%E5%A3%B3%20%2B%20CMP%20%E6%B7%B7%E6%8E%92-FF6F00)](#-核心架构原生壳--cmp-内容)
--- ## ✨ 这是什么 一个 **Kotlin Multiplatform + Compose Multiplatform** 的三端完整落地工程: - 🎯 **鸿蒙 NEXT 上真实跑通的 CMP 统一渲染**——华为 CPF-KMP-CMP 工具链(Kotlin `2.2.21-1.0.0`,含 `ohosArm64` 变体),KN 编译出 `libkn.so` 经 NAPI 宿主嵌入 ArkUI,公开资料稀缺,本仓库全程真机验证 - 🏗 **原生壳 + CMP 内容页混排**:启动页/Tab 栏保原生(三端各自最优体验),业务页三端同一份 Compose 组件——不追求"100% 一套",追求**每端都像原生 App** - 📺 **三端统一视频播放器**:一套 `XikaVideo` 声明式 API(playControl / rate / muted + 状态/进度/首帧回调),三端适配器 = ExoPlayer / AVPlayer / ArkUI Video,对齐腾讯 Kuikly Video 的接口设计 - 🧪 **真实数据源**:首页 wanAndroid 开放 API、视频 B 站解析直链 + 阿里云/iTunes 源、音乐 iTunes 试听——无假数据演示 - 📚 **完整踩坑复盘**:ComposeScene 崩溃、XComponent 原生断言、AVPlayer 状态机竞态、KN 依赖断流……每篇带现象/取证/根因/修复,都是真机趟出来的 > [!TIP] > 如果你正在调研「鸿蒙上能不能跑 CMP」「KMP 三端怎么混排」,直接看文末 [🧭 踩坑复盘](#-踩坑复盘精选)——那几篇 POSTMORTEM 比任何教程都真实。 ## 📺 效果演示 | Android(ExoPlayer) | iOS(AVPlayer) | 鸿蒙(ArkUI Video + CMP 混排) | |:---:|:---:|:---:| | 待补 GIF | 待补 GIF | 待补 GIF | ## 🧱 三端架构:原生壳 + CMP 内容 | 层 | 实现方 | 内容 | |---|---|---| | 启动页/引导页 | 各端原生 | Android `SplashActivity`(View)、iOS `SplashView/GuideView`(SwiftUI)、鸿蒙 `Splash.ets`(ArkUI) | | 主页 Tab 壳 | 各端原生 | 底部 4 Tab 导航;Tab 配置统一取自 sharedCore `TabConfigManager`(单一事实源) | | Tab 内容页 | **CMP(三端同一份)** | shared 模块 `XikaHomePageContent` / `VideoApp` / `MusicApp` / `MineApp` | | 视频播放 | 各端内核 + 统一 API | `XikaVideo` → Android ExoPlayer / iOS AVPlayer / 鸿蒙 ArkUI Video 原生播放页 | | 系统能力承接 | 各端原生 | H5 容器(WebView/WKWebView/ArkWeb)、音乐播放桥、网络引擎(OkHttp/Darwin/rcp) | ```mermaid flowchart LR subgraph native["三端原生壳"] A1["Android
TabBar + ComposeView"] A2["iOS
UITabBarController + CMP-VC"] A3["鸿蒙
ArkUI Tabs + Compose()"] end subgraph shared["shared / sharedCore (KMP, 一套代码)"] B1["CMP 内容页
home · video · music · mine (MVI)"] B2["XikaVideo 统一播放 API"] B3["网络(Ktor/wanAndroid) · 桥接协议 · TabConfig"] end subgraph kernel["平台内核"] C1["ExoPlayer"] C2["AVPlayer"] C3["ArkUI Video / NAPI(libkn.so)"] end A1 --> B1 A2 --> B1 A3 --> B1 B1 --> B2 B1 --> B3 B2 --> C1 B2 --> C2 B2 --> C3 ``` **CMP ↔ 原生交互契约(三端一致)**:`onSwitchTab(index)` 跨 Tab 跳转、`onNavigateH5(url)` H5 打开、`onOpenExternal(url)` 站外链接。 ## 📦 模块结构 ``` ├── sharedCore/ # ★ 逻辑核心(纯 Kotlin,无 UI):网络(Ktor)、桥接协议、领域模型、DI │ └── domain/home/ # HomeRepository(wanAndroid 实时数据) · TabConfig(Tab 单一事实源) ├── shared/ # ★ CMP 共享 UI 层(android + ios + ohosArm64) │ └── ui/ │ ├── home/ # XikaHomePageContent(首页卡片流,MVI) · 三态(加载/失败/内容) │ ├── video/ # 视频 Tab + XikaVideo 三端统一播放 API │ ├── music/ # 音乐 Tab(iTunes 30s 试听) │ ├── mine/ # 我的 Tab │ └── common/ # RemoteImage · MiniJsonParser(轻量 JSON 解析) ├── shared-login/ # 登录独立域模块(纯逻辑,四步授权链) ├── composeApp/ # 鸿蒙 CMP 宿主:@CName 导出 4 个 ArkUIViewController → libkn.so ├── androidApp/ # Android 壳:HomeActivity(原生 TabBar + 4 个常驻 ComposeView) ├── iosApp/ # iOS 壳:TabRootView(UITabBarController + 4 个 CMP controller,进程级缓存) ├── harmonyApp/ # 完整 DevEco 工程:Home.ets(原生 Tabs 壳)+ NAPI 宿主(libentry.so) ├── build-scripts/ # 构建/验证脚本 └── docs/ # 方案与复盘文档(见文末索引) ``` ## 📡 数据与能力 - **首页数据**:wanAndroid 开放 API(Banner + 文章瀑布流),纯远程、无本地 mock;失败显示失败态 + 重试 - **首页状态**:`HomeViewModel` 模块级单例 + `Init` 幂等——鸿蒙 surface 销毁重建(播放/切后台/息屏)后组合树重建时数据即时恢复,不闪加载页 - **视频**:三端统一 `XikaVideo` API(Kotlin 声明式,对齐 Kuikly Video 接口形状);源 = B 站解析直链(国内 CDN,运行时解析、签名时效约 2.5h)+ 阿里云演示片 + w3school 片段 + iTunes MV;鸿蒙端播放页内核为 ArkUI `Video` 组件(系统接管 prepare/缓冲时序) - **音乐**:iTunes 试听(30s m4a);Android MediaPlayer / iOS AVAudioPlayer / 鸿蒙 AudioHost(AVPlayer 桥) - **图片**:Android BitmapFactory 解码;鸿蒙/iOS 暂为首字占位(华为 CMP 构件缺 `Image.makeFromEncoded` 符号) ## 🚀 快速开始 前置环境:JDK 17+、Android SDK;鸿蒙需 DevEco Studio(含 ohos SDK/hdc);iOS 需完整 Xcode。 ### Android ```bash ./gradlew :androidApp:assembleDebug adb install -r androidApp/build/outputs/apk/debug/androidApp-debug.apk ``` ### 鸿蒙(release 链接,勿用 debug 产物,见「鸿蒙填坑清单」) ```bash # 1. 链接 libkn.so 并同步到鸿蒙工程 ./gradlew :composeApp:publishReleaseBinariesToHarmonyApp # 2. 构建 HAP(或在 DevEco Studio 中打开 harmonyApp/ 直接构建) cd harmonyApp && DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk \ /Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw \ --mode module -p module=entry@default -p product=default -p buildMode=debug assembleHap --no-daemon # 3. 安装启动 hdc install -r entry/build/default/outputs/default/entry-default-signed.hap hdc shell aa start -a EntryAbility -b # bundleName 见 AppScope/app.json5 ``` > 注意:`harmonyApp/entry/libs/`、`harmonyApp/entry/.cxx/`、`cpp/include/libkn_api.h` 为生成物,不入库;新 clone 后必须先执行第 1 步,否则 hvigor 原生编译缺符号。 ### iOS(需完整 Xcode) ```bash ./gradlew :shared:linkReleaseFrameworkIosSimulatorArm64 # 或由 Xcode Run Script 自动执行 # 打开 iosApp/KmpXika.xcodeproj 构建运行 ``` ### 单元测试 ```bash ./gradlew :sharedCore:testDebugUnitTest ``` ## 🧭 踩坑复盘(精选) > 每篇都是真机趟出来的:现象 → 被推翻的假设 → 取证过程 → 根因 → 修复 → 验证。 | 复盘 | 根因一句话 | |---|---| | [iOS 首启全链崩溃(5 层问题)](docs/IOS-CRASH-POSTMORTEM.md) | App 入口从未调用 `SharedGate.bootstrap()`,首页首次 watch 未注册订阅打死 ComposeScene(表象是误导性的 `ComposeScene is already closed`) | | [鸿蒙 CMP 崩溃复盘](docs/HARMONY-CRASH-POSTMORTEM.md) | KN 双 so 并存 = 双 runtime 互踩 SIGABRT;统一渲染下 XComponent 原生断言——合并为单一 libkn.so 是唯一正解 | | AVPlayer 状态机竞态(鸿蒙 v3) | `surfaceId/prepare/play` 必须严格按 `initialized → prepared` 状态回调时序,同步连调必炸 5400102 | | Gitee 拉取/KN 依赖断流 | CPF 工具链构件在华为 maven;大文件下载不支持续传,需换镜像重试 | ### 鸿蒙 CMP 填坑清单 - **单一 KN 运行时**:libkn.so 内含全部逻辑层(export shared);同进程禁止双 runtime——双 so 并存 = SEGV/死锁 - **skikobridge 链接**:宿主 CMake 必须链接 `compose::skikobridge`,否则 CMP 组件首次挂载即 SEGV - **生命周期转发**:宿主页必须转发 onPageShow/Hide、onSurfaceShow/Hide 给 controller,否则启动/锁屏异常 - **release 链接**:debug 产物存在 skia FontCollection 部分链接崩溃(IrLinkageError),鸿蒙包一律用 release 产物 - **状态保留**:surface 重建 → 组合树重建是平台确定性行为,靠 ViewModel 单例 + Intent 幂等兜底;Navigation 承载方案已验证并回退 ## 📖 文档索引 | 文档 | 内容 | |---|---| | [docs/HUAWEI-KMP-CMP-SOLUTION.md](docs/HUAWEI-KMP-CMP-SOLUTION.md) | 华为 KMP&CMP 方案详解(工具链/架构/接线六步/坑清单) | | [docs/HUAWEI-CMP-MIGRATION.md](docs/HUAWEI-CMP-MIGRATION.md) | CMP 迁移设计与进度 | | [docs/CMP-HOME-MVI-DESIGN.md](docs/CMP-HOME-MVI-DESIGN.md) | 首页 MVI 架构设计 | | [docs/CMP-ASSESSMENT.md](docs/CMP-ASSESSMENT.md) | CMP 选型评估(结论反转记录) | | [docs/HARMONY-CRASH-POSTMORTEM.md](docs/HARMONY-CRASH-POSTMORTEM.md) | 鸿蒙崩溃复盘(skikobridge 缺链定位全过程) | | [docs/IOS-CRASH-POSTMORTEM.md](docs/IOS-CRASH-POSTMORTEM.md) | iOS 首启 5 层问题全链复盘 | | [docs/KMP-NETWORK-DESIGN.md](docs/KMP-NETWORK-DESIGN.md) | 网络层设计 | | [docs/LOGIN-MODULE-DESIGN.md](docs/LOGIN-MODULE-DESIGN.md) | 登录域独立模块设计 | | [docs/TARGET-ACTION-MIGRATION.md](docs/TARGET-ACTION-MIGRATION.md) | 路由协议迁移 | | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | 逻辑层架构学习指南 | | [harmonyApp/README.md](harmonyApp/README.md) | 鸿蒙工程构建细节 | ## ⭐ 支持一下 如果这个仓库帮你少踩了坑,欢迎点个 Star —— 鸿蒙 × CMP 的公开实践还太少,你的 star 能让更多正在填坑的人搜到它。 ---
**Kotlin 跨端 · 鸿蒙生态 · 持续填坑中**