跨端页面如何做到“秒开“?详解腾讯 Kuikly 的 TurboDisplay 首屏加速方案

6 阅读5分钟

Kuikly是腾讯基于 Kotlin Multiplatform(KMP) ​ 构建的跨平台 UI 框架,一套代码可覆盖 Android、iOS、HarmonyOS、H5、微信小程序和 MAC。得益于 Kotlin/Native 编译产物直接对接原生渲染管线,Kuikly 本身已具备原生级性能。

但在首屏打开链路上——容器初始化 → 运行时准备 → 业务代码执行 → 数据请求 → 布局测量 → 节点构建 → 上屏——任何一环的耗时都会变成用户可感知的白屏等待。单纯让"代码跑得更快"已逼近收益天花板,要从根本上加速,必须从渲染链路的调度方式入手。

为此 Kuikly 推出了自研首屏加速方案 TurboDisplay,在页面二次打开场景下实现"打开即可见、可交互",已在 QQ 游戏、搜狗输入法、腾讯地图等产品中取得 60%~80% 的首屏耗时优化


一、为什么传统优化做不到"秒开"

业界常见的手段各有局限:

方案作用不足
Bitmap / 截图占位立即给视觉反馈不可滚动、不可交互,非真实页面
接口数据缓存省去网络等待不覆盖业务执行、布局测量、节点构建
Skeleton / Loading缓解焦虑感没有缩短可交互时间

真正的"秒开"要求缓存对象不只是图片或数据,而是框架渲染产物本身——已构建好的渲染节点树,下次打开直接呈现可交互内容。这就是 TurboDisplay 的设计起点。


二、为什么简单的"节点直出"还不够

最直观的思路是把渲染节点树序列化落盘,下次打开反序列化直接重建视图,跳过"执行业务代码 → 布局测量 → 节点构建"。

但这只能缩短跨端侧业务执行时间,前置的引擎/容器初始化仍无法省略,首屏还是会受阻塞。且缓存恢复仍嵌套在原执行链路中——本质上只是"跑得快一点",并没有重构链路。

TurboDisplay 的核心改进是:把缓存恢复从主链路中拆出,形成独立快速路径,并与原执行链路并行工作。


三、TurboDisplay 三大核心机制

3.1 双线并行

容器及根 View 构建完成后:

  • 端侧快速路径:立即读取本地缓存 → 反序列化为节点树 → 发渲染指令 → 首屏直出
  • 跨端侧后台路径:照常执行真实页面的业务逻辑、布局测量、节点构建,生成真实节点树;
  • 后台完成后与缓存节点树做 diff,将差异增量更新到屏幕上。

这样用户第一时间看到可交互的首屏,后台逻辑不影响展示时机。

3.2 节点采集

TurboDisplay 缓存的是端侧节点树上完整节点信息

  • 节点属性(颜色、字号、可见性等)
  • 绑定事件(点击、滑动)
  • 布局 Frame、Shadow 信息
  • 节点方法调用、树结构变化

采集时自动比对缓存首屏与真实首屏的树差异,限频写盘。业务可配置是否捕获结构差异,在缓存体积与新鲜度间取舍。

3.3 增量更新

为避免真实页面覆盖缓存时产生闪屏或跳变,TurboDisplay 采用局部 diff 更新:

  • 跨端侧构建真实节点树后与缓存树比对属性 / Frame / 方法参数差异
  • 全量回放首屏期间暂存的交互事件
  • 仅新建缺失节点,不做整体替换

实现缓存首屏 → 真实首屏的无感平滑切换


四、状态恢复与延迟 Diff

实际场景中用户可能已滚动列表或触发交互,缓存首屏处于非默认状态,而跨端侧构建的真实页仍在默认位置。若直接 diff,"端侧交互态 vs 默认态"的差异会导致首屏被强制重置回默认——表现为位置跳变。

TurboDisplay 的解法是由跨端侧调度 Diff 时机:在生成渲染指令前,先将滚动偏移量、暂存交互事件应用到真实页节点,使两端对比基准一致,再执行 diff。此时非默认内容不再是差异项,不会被错误覆盖。


五、性能数据

实验室测试(页面二次打开):iPhone 13 Pro Max / iPhone 7 Plus 均实现首帧即现。

线上业务数据(逻辑与数据均已本地缓存,无网络耗时):

业务页面优化前(ms)优化后(ms)降幅
腾讯地图-页面A2814882.9%
QQ游戏-页面B1464072.6%
QQ游戏-页面C1163272.4%
输入法-页面A1264266.7%
输入法-页面B541766.7%

六、接入方式

TurboDisplay 设计为业务无侵入,Native 容器侧仅需实现一个 Key 接口即可开启:

// iOS KuiklyRenderViewController
- (NSString *)turboDisplayKey {
    return @"pageName";  // 返回唯一页面标识
}

Kotlin 侧可通过 turboDisplayConfig()设置 KRTurboDisplayConfig.turboDisplayKey


七、小结

TurboDisplay 的本质是渲染节点缓存 + 端侧直出 + 双线程并行 + 延迟 Diff,跳出"优化执行速度"的思维定势,从链路调度层面实现二次打开秒开。目前主要覆盖二次打开场景,首次打开加速(编译期首屏提取 + 微指令引擎)也在规划中。