在探索三端(Android / iOS / Harmony)统一开发的道路上,我们最终选择了 KMP + Kuikly 实现 UI 跨平台,并结合 Rust 实现核心下载逻辑,形成了高性能、可扩展的混合架构
一、项目背景
在我们的直播项目中,有下载模块的需求。它需要同时运行在 Android、iOS、HarmonyOS 三个平台上,并满足以下目标:统一的交互体验与视觉样式;稳定可靠的下载逻辑(支持断点续传、任务恢复、缓存清理);易于维护与扩展(减少多端重复开发成本)。
传统的「多端独立实现」开发效率低、维护成本高,更关键的是:一旦交互逻辑或界面更新,需要三端同时修改,极易引发版本差异和一致性问题。因此,我们决定采用跨平台方案统一开发。
二、为什么不是 Flutter,而是 KMP + Kuikly
在我们的项目中,Flutter 已经被广泛使用,主要应用于登录、注册、设置、个人资料等非直播间场景。
然而,在实际应用 Flutter 过程中,我们遇到了一些问题:
- iOS 端接入 Flutter 后,内存大幅上涨,包体积显著增加;
- 基于 Skia 引擎的 Flutter 在 iOS 端无法复用系统着色器,部分界面出现渲染卡顿;
- Flutter 与原生音视频模块、文件系统等交互复杂;
- HarmonyOS 支持仍不完善,跨端适配存在限制;
这些痛点在我们的场景尤为明显,因为 UI 与端原生控件和系统服务紧密绑定,对性能和一致性要求极高。
1️⃣ Flutter 的优势与局限
Flutter 优势:
- 开发效率高,适合中轻量级界面;
- 跨平台 UI 一致性好,渲染性能在多数场景下优秀。
局限:
- 深度系统交互复杂,性能不稳定;
- 大项目包体积大,维护成本高;
- HarmonyOS 支持不足,无法完全覆盖三端;
2️⃣ KMP 的优势与架构选择
KMP(Kotlin Multiplatform)允许在多个平台间共享 Kotlin 代码。
在直播间项目中,我们采用了 “UI 跨端 + 逻辑层 Rust” 的架构:
UI 层由 KMP 统一编写,逻辑层(下载、缓存、任务调度)由 Rust 实现。
这种架构的优势:
- 性能:Rust 提供底层高性能支持,保证下载和缓存逻辑稳定可靠;
- 可维护性:Kotlin 层可快速迭代 UI 与交互逻辑;
- 跨端一致性:结合 Kuikly,三端 UI 保持完全一致;
- 扩展性:后续功能扩展或平台增加,无需重复开发逻辑层。
三、为什么选择 Kuikly
原生 KMP 目前仍未支持 Harmony 平台,这成为我们的主要限制。
腾讯开源的 Kuikly 框架 刚好补齐了这一空白。
Kuikly 基于 KMP 架构,提供了一套跨平台 UI 层方案:
| 特性 | 说明 |
|---|---|
| 跨端 UI DSL | 一套 Kotlin 代码自动生成 Android/iOS/Harmony UI |
| 原生控件渲染 | 底层仍是平台原生控件,无性能损耗 |
| Harmony 支持 | 已支持三端编译链路 |
| 可混编 Rust / C++ | 支持跨语言桥接 |
| 一致的生命周期与状态流转 | 避免三端生命周期差异导致的状态错乱 |
一句话总结:Kuikly = 让 Kotlin 写的 UI 真正跨三端运行
四、架构设计
最终我们形成了如下混合架构:
KMP + Kuikly 层负责:
-
下载 UI(任务列表、进度条、状态切换、错误提示);
-
状态同步与界面刷新(通过 StateFlow);
-
用户交互(暂停、恢复、重试等事件)。
Rust 层负责:
- 实际下载任务的执行;
- 断点续传;
- 缓存清理与校验;
- 数据回调(通过 FFI 传递回 Kotlin)。
五、下载 UI 的实现细节
以「下载管理页」为例,我们采用 Kuikly DSL 构建 UI:
@Composable
fun DownloadTaskItem(task: DownloadTask, onAction: (TaskAction) -> Unit) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(16.dp)
) {
Text(task.title, modifier = Modifier.weight(1f))
ProgressBar(progress = task.progress)
Button(
text = if (task.isPaused) "继续" else "暂停",
onClick = { onAction(if (task.isPaused) Resume else Pause) }
)
}
}
Kuikly 会自动生成三端原生 UI(Android → ComposeView,iOS → SwiftUI,Harmony → ArkUI)。
交互链路:
- 用户点击“暂停”;
- Kuikly 触发 Kotlin ViewModel;
- ViewModel 调用 Rust FFI 暂停任务;
- Rust 引擎更新任务状态;
- 状态回传 → StateFlow → UI 自动刷新。
六、开发中遇到的问题与解决
1. iOS Framework 编译失败
问题:
KMP 工程导出的 framework 在组件化 iOS 项目中引入后,出现符号找不到、依赖链错误等问题。
原因:
Kuikly 生成的 iOS 产物默认依赖静态链接的 Kotlin runtime,若目标工程未引入 KotlinNativeFramework,会导致链接错误。
解决方案:
- 在主工程中显式引入 kotlinstdlib;
- 调整生成配置为 Dynamic Framework;
- 统一 iOS 模块的 bitcode 与架构选项(arm64、x86_64)。
2. 字段与数据模型统一问题
由于 Android、iOS、Harmony 三端原始接口字段不完全一致(命名或类型差异),导致共享模型解析异常。
解决方案:
- 在 KMP 层定义统一的数据模型;
- 使用 @SerialName 注解做字段映射;
- 提供 PlatformAdapter 层统一类型转换。
3. Harmony 平台编译链路问题
Harmony 模块引入时,出现 CMake / Kotlin 编译链冲突(尤其在 Kuikly early-access 版本)。
解决方案:
- 升级至 Kuikly 稳定版本;
- 调整 Harmony Gradle 插件顺序;
- 将 shared.so 模块通过本地依赖引入,避免远程构建差异。
七、效果与收益
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 三端 UI 代码复用率 | 约 15% | 85%+ |
| 界面一致性问题 | 多端差异明显 | 完全统一 |
| 性能(FPS/功耗) | Flutter 稍优 | 与原生持平 |
同时,得益于 Kuikly 的原生渲染机制,UI 无需额外渲染层,帧率与功耗几乎等同原生实现。
八、总结与展望
通过 KMP + Kuikly,我们实现了:
-
一套 UI 代码,覆盖 Android / iOS / Harmony;
-
Kotlin 层管理状态与交互;
-
Rust 层承载下载逻辑;
-
跨端一致、性能接近原生的用户体验;
-
为后续新的跨平台UI技术提供基础和经验。