一、背景:KMP + Rust 的协同挑战
在上篇中我们提到,项目采用了 KMP + Kuikly 来实现跨端 UI,而底层下载逻辑则由 Rust 实现。这样做的好处是,KMP 提供灵活的多端 UI 框架和 Kotlin 语言生态,Rust 则保证了性能与安全性。
但这种组合也带来了不少挑战:KMP 与 Rust 跨语言边界复杂 (Kotlin/Native + FFI); 线程模型不一致 ,Rust 任务是异步的,而 KMP 要保证在主线程安全更新 UI; 跨端数据结构对齐问题 (尤其是 iOS Framework 集成); 下载状态同步延迟与 UI 刷新频率不匹配。
二、架构设计:双层跨平台协作模型
我们最终采用了"双层协作"架构:

在此架构中:UI 层(KMP) :负责渲染下载任务界面、任务状态、进度条、错误提示; 逻辑层(Rust) :负责真实的文件下载、断点续传、缓存与任务调度; 桥接层(JNI / C-API) :我们在此定义了一套统一的接口规范(包括状态同步、回调分发、错误码映射),保证跨平台一致性。
三、架构设计思路
统一状态流模型
Rust 下载引擎在底层会通过 tokio::mpsc::channel 推送任务状态,而在 KMP 侧,我们用 StateFlow 做统一封装:
kotlin
// Kotlin ViewModel 层
val downloadState = MutableStateFlow(DownloadState.Idle)
fun observeDownload(taskId: String) {
rustBridge.subscribe(taskId) { stateJson ->
val state = json.decodeFromString<DownloadState>(stateJson)
downloadState.value = state
}
}
这种 "Rust → KMP → Compose/Kuikly" 的状态流式架构,让 UI 层完全响应式更新,不卡主线程,也便于灰度监控。
跨语言回调安全机制
Rust 调用 Kotlin 层时可能会发生线程切换或生命周期不一致问题。
为此我们在桥接层设计了 回调代理层(Callback Dispatcher) :
rust
// Rust 层调用 Kotlin 的桥接方法
extern "C" fn on_progress(task_id: *const c_char, progress: f32) {
kotlin_notify_progress(task_id, progress);
}
kotlin
// Kotlin 侧接收并调度到主线程
fun kotlin_notify_progress(taskId: String, progress: Float) {
mainScope.launch {
_downloadProgress[taskId]?.emit(progress)
}
}
保证:所有 UI 更新都安全地在主线程执行;回调生命周期与 KMP 层 ViewModel 解耦; 避免内存泄漏或野指针。
桥接层接口规范化
为了避免 Android/iOS/Harmony 三端分别实现不同桥接逻辑,我们在 Kotlin 层定义了一套中间层协议接口:
kotlin
interface IRustDownloader {
fun init(config: DownloadConfig)
fun startTask(url: String, dest: String)
fun pauseTask(taskId: String)
fun observeProgress(taskId: String, listener: (Float) -> Unit)
}
每个平台只需各自注册一套 native 接口即可。这种方式: 降低多端集成复杂度; 便于未来替换引擎(如改用 C++ 或其他方案); 强化工程的可维护性。
四、集成与性能表现
性能上单任务下载性能 :比旧的 Java 下载模块提升约 30%--40% ; 并发任务性能 :Rust 异步任务模型几乎无锁竞争; 内存占用 :峰值降低约 20% ; 包体积增量 :约 1.8MB(Android) ,2.1MB(iOS Framework) 。
灰度策略采用新老下载引擎共存;通过特征开关(Feature Flag)动态切换; A/B 实验验证 QoE 指标(下载成功率、任务耗时、CPU 占用)。
五、开发中遇到的实际问题
问题 | 解决方案 |
---|---|
iOS Framework 编译失败 | Rust 生成的 .a 静态库与 Swift 组件化工程冲突,改为动态 Framework 并使用 cbindgen 生成头文件。 |
Harmony 平台 NDK 缺失 | Kuikly 工具链支持 Harmony,需手动增加 Rust target 并适配 musl 编译链。 |
Kotlin/Native 回调崩溃 | 增加回调代理层,所有回调都通过主线程调度执行。 |
下载状态丢失 | Rust 侧持久化任务信息(SQLite),KMP 层启动时重新同步。 |
六、总结
这套 KMP + Rust 协作模型 实现了三端 UI 一致、逻辑统一;下载引擎性能与稳定性显著提升;桥接层接口清晰、可扩展性强,为后续的跨平台开发铺设奠定了基础。