首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >KuiklyUI Render 层的跨平台落地设计

KuiklyUI Render 层的跨平台落地设计

原创
作者头像
骑猪耍太极
发布2026-07-12 12:52:23
发布2026-07-12 12:52:23
1940
举报

上一篇文章把 Bridge 协议拆开看了一遍。Core 发出的所有指令,最后都会变成 23 个 methodId 里的某一个。Bridge 本身只负责把指令送到边界,把这些指令转换为屏幕上的 UI,还要靠 Render 层。

Render 层是 KuiklyUI 里贴近平台的一层。它不再追求一份代码跑多端,而是每个平台用自己的语言、自己的 UI 系统、自己的线程模型来实现同一套协议。

这一篇不深入某一个平台的全部细节,而是横向看四个平台:Android、iOS、鸿蒙和 Web。重点放在它们哪里同构,哪里不同,以及为什么需要这些不同。


一、Render 的共同职责

先把共同部分说清楚。无论平台怎么不同,Render 层都要完成四件事。

  • 接收 Bridge 下发的 17 个 NativeMethod。比如 CREATE_RENDER_VIEWSET_VIEW_PROPINSERT_SUB_RENDER_VIEWSET_RENDER_VIEW_FRAMECALL_MODULE_METHOD。这些 method 在 Core 侧已经固定,Render 需要按相同语义实现。
  • 维护一张 view 索引表。Core 侧用 nativeRef 标识每个 View,Render 侧要用同一个 tag 找到对应的平台对象。各端可以用自己的 Map / 字典结构实现,文章里不展开具体容器类型。
  • 把属性翻译成平台 API。比如同一个 backgroundColor,到 Android 是 View 属性设置,到 iOS 是 UIView 属性设置,到 Web 是 CSS,到鸿蒙是 ArkUI 的节点属性。属性名来自同一套协议,实现方式完全不同。
  • 处理事件反向回传。Render 注册原生点击、滚动、触摸等事件,触发后再通过 FIRE_VIEW_EVENT 回到 Kotlin 侧。

这几个职责确定之后,各平台实现虽然语言不同,但骨架是同构的。

四平台 NativeBridge actual 对比
四平台 NativeBridge actual 对比

二、同一套骨架,四种语言实现

KuiklyUI 的 Render 层有一个明确特点:架构同构,实现各异。

Android 用 Kotlin 和 Java,直接对接 Android View 体系。iOS 用 Objective-C / Objective-C++,对接 UIKit 和 CocoaPods 里的 Kotlin/Native framework。鸿蒙用 C++ 为主、ArkTS 为辅,通过跨语言调用和 ArkUI 原生接口协作。Web 用 Kotlin/JS,对接 DOM 和小程序的数据更新模型。

这不是技术栈不统一,而是边界划分后的结果。Render 层要深度操作平台 UI,使用平台团队最熟悉的语言通常更稳。Android View、UIKit、ArkUI、DOM 的生命周期、事件、线程模型都不同,强行用同一种语言抹平它们,未必能减少复杂度。

所以 KuiklyUI 的统一点放在协议上,而不是实现语言上。Core 发出的 17 个 method 是统一的;每个平台收到 method 之后,怎么创建 UI 对象、怎么设置属性、怎么调度线程,由各端自行处理。

Render 层四端落地方式
Render 层四端落地方式

Render 层的工程策略很明确:接口在 Core 侧统一,实现由各平台自行处理。


三、Android Render 的 JVM 路径

Android 是几端里比较容易理解的一端。业务 Kotlin 和 Render Kotlin 都跑在 JVM 里,JVM 模式下 Bridge 基本就是同进程方法调用。宿主只需要创建一个顶层渲染容器,把它按普通 Android View 的方式添加到 Activity 或 Fragment 中。源码里这个顶层容器叫 KuiklyRenderView

Android Render 内部大致分三层。先看名字,再看职责:

代码语言:bash
复制
KuiklyRenderView
  ↓
KuiklyRenderCore
  ↓
KuiklyRenderLayerHandler
  ↓
RenderViewHandler / android.view.View

这三个名字可以按职责理解:KuiklyRenderCore 是分发中心,负责接住 Bridge 下发的 17 个 method;KuiklyRenderLayerHandler 是 View 树管理器,负责按 tag 创建 View、插入子 View、设置属性和 frame;RenderViewHandler 是单个原生 View 外面的一层包装,用来记录属性、处理复用等细节。

Android 端有两个值得注意的点。

一个是双线程模型。业务 Kotlin 代码运行在框架自己的 Context 线程里,真正操作 Android View 时再切回 UI 线程。Render 层会把大部分 UI 操作投递到 UI 调度器里批量执行。这样业务逻辑不阻塞主线程,UI 修改也符合 Android 线程约束。

另一个是复用池。Android View 创建成本不低,List 场景又很容易频繁创建和销毁节点。Render 层会尽量复用同类型 View,复用前再清理旧属性。这个设计和 Android RecyclerView 的经验是一脉相承的。


四、iOS Render 保持同构但处理 UIKit 细节

iOS Render 的整体骨架和 Android 对应:同样有顶层渲染容器、method 分发中心和 UIView 树管理器。源码里的名字也和 Android 一一对应,但读这篇文章只需要抓住职责,不必记住每个类名。

不同的是,iOS 业务 Kotlin 会编译成 Kotlin/Native framework,再通过 CocoaPods 进入 iOS 工程。ObjC 侧通过 Kotlin/Native 暴露出来的入口类调用 Core。这个桥接路径比 Android 多一层 Kotlin/Native 到 ObjC 的互操作,但整体角色没有变。

iOS 端也有两条执行队列:一条跑业务侧回调和 Bridge 分发,另一条回到主线程操作 UIKit。这个模型和 Android 的 Context 线程 / UI 线程是对应的。

iOS 的复杂点集中在 UIKit 和 CALayer 细节上。典型例子是圆角和阴影:圆角裁剪和阴影绘制在 iOS 图形系统里天然有冲突,KuiklyUI iOS Render 会在需要同时支持圆角和阴影时自动包一层额外 view。外层负责阴影,内层负责圆角和裁剪。

这类处理说明 Render 层不能只是机械地翻译属性。每个平台都有自己的图形系统约束,Render 需要把统一属性翻译成平台上实际可工作的结构。


五、鸿蒙 Render 的三语言协作

鸿蒙端的复杂度来自三种语言协作:ArkTS、C++ 和 Kotlin/Native。

业务 Kotlin 会编译成动态库,Render 主体也是 C++ 动态库。ArkTS 侧主要提供入口组件和少量必须使用 ArkTS API 的能力。核心渲染逻辑尽量放在 C++,再通过 ArkUI 的原生接口创建和操作节点。

简化后的路径是:

代码语言:bash
复制
ArkTS 入口组件
  ↓ 跨语言调用
C++ Render
  ↓ 加载业务 Kotlin 动态库
Kotlin/Native 业务代码
  ↓
C++ Render 接收 Core 指令
  ↓ ArkUI 原生接口
ArkUI 节点

这个结构看起来绕,但背后有明确的性能考量。鸿蒙上的跨语言调用成本不低,如果每次设置属性都从 C++ 穿到 ArkTS,再由 ArkTS 操作 UI,Bridge 成本会很快放大。所以 KuiklyUI 选择让 C++ 尽可能直接调用 ArkUI 的原生接口,ArkTS 只保留必要入口。

鸿蒙还暴露出一些协议层面的特殊处理。比如 CALL_MODULE_METHOD 的参数槽位已经用满,但鸿蒙端又需要额外携带“同步调用”和“回调是否保留”两个信息,于是把这两个含义压到同一个整数里。这个细节不是为了炫技,而是在固定 6 槽位协议下做的适配。

鸿蒙端的代价也明显:C++ 代码量大,三种语言的内存模型不同,调试和崩溃定位都更复杂。Render 层在这里承担的不只是 UI 翻译,还有大量平台工程问题。


六、Web Render 的两种落地方式

Web 端的 Bridge 开销较低。业务 Kotlin 编译成 JS,Render 也编译成 JS,最终都在同一个 JS 引擎里运行。Core 调 Render,本质是 JS 函数调用,不需要 Android、iOS、鸿蒙那类跨语言互操作。

H5 场景下,Render 的实现比较直接:创建 DOM 节点、设置 CSS、注册 DOM 事件。KuiklyUI 里的 View、Text 等组件,最终会落到浏览器能理解的标签和样式上。虽然浏览器本身有 Flex 布局,但 KuiklyUI 仍然使用 Kotlin 侧算好的 frame,以保证和 Native 端一致。

Web 端的大头在 CSS 翻译。颜色、圆角、transform、阴影、字体、文本对齐、事件名,这些统一属性都要转换成浏览器能理解的 CSS 或 DOM API。Web 端代码量不一定大,但属性映射非常细。

小程序则不同。小程序没有传统 DOM,逻辑层不能直接操作渲染层,只能提交一份数据让渲染层更新。如果每次 SET_VIEW_PROP 都立即提交,容易形成频繁更新。KuiklyUI 在小程序端需要把一帧内的多次属性和 frame 更新合并,再一次性 flush 到渲染层。

所以 Web 端不是只有一个实现。H5 偏直接 DOM 操作,小程序偏数据驱动,两者共享 base 层,但最终落地方式不同。


七、View 创建与 Module 实现的差异

CREATE_RENDER_VIEW 看四端差异很清楚。

Android 会通过注册中心按 viewName 创建 Android View,并尝试走复用池。iOS 会按 viewName 找到对应的 UIView 类型并创建实例。鸿蒙侧会创建 ArkUI 节点。H5 会创建 DOM 元素,小程序则创建一份渲染层能消费的数据节点。

同一个文本组件,最后在不同平台会变成不同的原生文本对象。可能是 Android 的文本 View、iOS 的文本控件、鸿蒙的 ArkUI 文本节点,也可能是 Web 或小程序里的文本节点。Core 不关心这些对象具体叫什么,只关心 tag 和属性是否能按协议生效。

Module 也是同样的模式。Kotlin 侧只看到统一的网络、路由、存储等 API;真正落到平台上时,Android、iOS、鸿蒙、Web 会各自选择本平台合适的网络库、路由能力或存储能力。平台差异全部被 Render 的 Module 实现吸收。

这条边界也比较清楚:共享层负责表达意图,平台层负责用本平台合适的方式完成。


八、Render 层的设计取舍

Render 层的核心取舍,是各平台独立实现,而不是强行把渲染层也做成一份共享代码。

这样做的收益明确。平台团队可以用熟悉的语言写贴近系统的代码;遇到 UIKit、RecyclerView、ArkUI、DOM 这种平台细节时,不需要绕一层抽象;某个平台修 bug 也可以独立发布。

代价也很明确。新增一个基础组件,需要四端分别实现。一个属性在 iOS 表现异常,可能要对照 Android、鸿蒙、Web 才能判断是 Core 协议问题还是 iOS Render 翻译问题。维护成本从一份共享代码变成多份平台代码。

KuiklyUI 之所以能承受这个成本,是因为 Bridge 协议足够稳定,Render 骨架足够同构。四端虽然语言不同,但都围绕同一组 method、同一种 tag 索引、同一类调度时机工作。差异被限制在平台实现内部,而不是扩散到业务 API。


总结

Render 层把 Bridge 下发的固定 method 翻译成 Android View、UIKit View、ArkUI 节点、DOM 或小程序数据树。四端共享的部分是协议、tag 索引、method 分发和事件回传;不同的部分是语言、线程模型、UI 对象、属性映射和平台优化。Android 重视双线程和复用池,iOS 处理图形系统细节,鸿蒙用 C++ 主导来减少跨语言成本,Web 则在 DOM 和小程序数据更新之间分出两套落地路径。

这组架构把跨端分成了三层:Core 决定要做什么,Bridge 规定怎么通信,Render 管怎么落到平台上。

下一篇会回到 Core 内部,看 KuiklyUI 为什么自研一套轻量协程,以及这套协程如何和 Pager 生命周期、Bridge 回调配合。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Render 的共同职责
  • 二、同一套骨架,四种语言实现
  • 三、Android Render 的 JVM 路径
  • 四、iOS Render 保持同构但处理 UIKit 细节
  • 五、鸿蒙 Render 的三语言协作
  • 六、Web Render 的两种落地方式
  • 七、View 创建与 Module 实现的差异
  • 八、Render 层的设计取舍
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档