直播APP跨平台架构实践(一):从 Flutter 到 KMP + Kuikly 的落地

475 阅读5分钟

在探索三端(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 真正跨三端运行

四、架构设计

Untitled diagram-2025-10-22-104648.png

最终我们形成了如下混合架构:

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)。

交互链路:

  1. 用户点击“暂停”;
  2. Kuikly 触发 Kotlin ViewModel;
  3. ViewModel 调用 Rust FFI 暂停任务;
  4. Rust 引擎更新任务状态;
  5. 状态回传 → 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技术提供基础和经验。