当前位置: 首页 > Web前端 > HTML

Cube技术解读-“支付宝”全新卡牌技术栈详解

时间:2023-03-28 16:20:43 HTML

CodeHub#7正式结束,蚂蚁集团技术专家“景军”与掘金社区开发者分享“支付宝”全新卡牌技术栈——魔方卡(Cube).Jingjun围绕Cube技术的架构逻辑讲解了渲染制作过程,并引导开发者完成了前期的技术调试。?点击播放观看CodeHub#7的完整回放;公众号mPaaS后台回复“魔方”,获取讲师完整PPT。动态卡片的背景从Windows时代开始,应用图标就成为了用户(流量)的主要入口,一直延续到移动时代。图标作为入口的方式的缺点是不直观,至少需要点击一下才能访问到想要的信息。在这样的背景下,iOS系统和部分Android系统实现了将内容和服务放在面前的卡片,如下图所示:此外,鸿蒙系统也提出了类似的卡片场景作为流量入口。其实更多的是APP内部的卡片作为内容展示和服务入口,比如支付宝首页、招商银行理财页面,每个小矩形就是一张卡片。对于运营来说,卡片样式和内容可以随时配置,无需等待应用版本升级,这也是刚需。Cube概述Cube是蚂蚁集团内部研发的一套跨平台的动态卡片解决方案。它是一种服务于应用页面的区域动态技术。以内容为导向,帮助产品技术提升开发效率。和运营效率。每张魔方卡片(Cube)独立嵌入原生页面的一个区域,通过卡片模板展示该区域的内容。这里先说一下高性能。Cube追求的是贴近原生的体验。我们定义了两个维度:一个是极致表现。我们在魔方小程序能力的基础上,去掉了一些复杂的css能力,比如伪类伪元素、inline/block等,同时也限制了js的能力(魔方卡使用quickjs作为脚本引擎).此外,我们还对quickjs做了一些优化,包括不限于离线原子编译优化、异步gc优化等。我们还引入了wamr作为quickjs的“协处理器”,支持用户使用javascript和assemblyscript进行混合开发.这样用户就可以使用assemblyscript的一些热门函数或模块了。另一个维度是极致记忆力。在无限下拉的信息瀑布场景中,魔方卡的内存增长与原生卡接近。我们对卡的能力进行了更细粒度的分类,并通过在开发过程中配置它们来减少运行时的内存消耗。下图是一张简单的卡片,如图所示的魔方卡片的工程目录,以及钱包中某张卡片的真实代码和运行效果。魔方卡片制作&工作流程研发期本地开发魔方卡片(Cube)自带独立开发工具,支持卡片编译、日志输出、实时预览等功能。Vue作为目前开发模板的dsl语言,支持js和css编辑卡片样式。卡片管理卡片本地开发完成后,通过卡片管理后台上传发布卡片编译产品,可以对卡片版本进行管理。卡片发布后,可以在客户端动态更新卡片。在运行期间,为了方便终端业务接入魔方卡,我们引入了魔方卡容器(CardSDK)的概念。CardSDK封装了一些与业务层/服务端密切相关的通用能力。比如我们通过CubeCardSdk从服务端拉取卡片和业务数据。另外,CardSDK还负责常用的JSAPI和第三方组件的接入。这样一来,魔方卡片就可以更加专注于卡片产品本身。核心系统架构魔方的系统架构主要包括JSEngine、CardEngine、RenderEngine和Platform,大部分代码是用C++实现的。JSEngine主要负责卡片js逻辑执行和卡片数据变化监控,以支持开发者在卡片内部编写一些业务逻辑能力,实现卡片内容和样式的动态变化。由于卡片场景对性能要求较高,综合考虑包大小和性能,我们选择了quickjs作为我们的js基础引擎库,同时实现了一个非常小的js响应式框架(JSFM)来支持卡片内逻辑代码能力.CardEngine主要负责卡片数据解析绑定、卡片逻辑渲染、构建DOM指令、JSAPI管理、JSBinding、Native事件通信等,在卡片DOM树的初始构建过程中,我们并没有放到js运行时,而是在卡片实例初始化环节直接使用C++生成指令并构建树。一方面是为了让js框架更小更快。另一方面,C++运行效率更高。RenderEngine后端渲染库负责卡片布局计算、样式分析、Layer计算、自绘组件、同层渲染、屏幕光栅化等过程,以及手势、动效等交互效果。Platform平台相关接口,包括原子视图封装、CanvasAPI、三方组件扩展协议、动画API等。线程模型与数据模型线程模型魔方卡(Cube)生命周期中的主要线程包括业务线程和引擎线程。业务线程是卡片数据的初始化阶段,由业务发起。这是卡片生命周期的beforeCreate阶段。engine线程是card生命周期所有运行阶段的公共线程,主要包括Bridge线程、Render线程、Paint线程和UI主线程。Bridge线程js运行线程也是Dom节点数据查询和处理线程。因为基于魔方卡片小而快的定位,js逻辑只是卡片的辅助能力,并没有太复杂的业务逻辑能力,所以Bridge线程比较轻,并且设计成单-螺纹。Render线程负责渲染相关的数据计算线程,包括渲染树构建、节点层级计算、Layer分层绘制计算、手势数据计算、渲染任务构建。Render过程主要涉及树的递归计算过程,相对于渲染过程耗时非常短。为单线程模式设计。Paintthread是执行卡片节点分层绘制和光栅化任务的绘图线程。Paint线程不是固定线程。根据目前的任务模型,Paint线程可能是主线程,也可能是线程池中的子线程;同步渲染模式下,Paint线程直接为主线程;在异步渲染模式下,通过线程池实现Paint任务的并发渲染,提高渲染效率,比如在列表滑动场景中。UI主线程UI操作的主线程是当前平台线程,主要包括手势识别、UI投屏和三方扩展组件的数据更新。除了上面涉及的主线程外,还有埋点和监控相关的playground后台线程,整体优先级比较低。整体线程模型设计,最大程度降低UI主线程压力,提高并发卡片渲染效率。但是还存在一些不足,包括UI线程切换频繁,Bridge线程越来越重等,后续我们会继续优化线程模型。数据模型和线程模型对应的数据模型主要包括三棵树:NodeTree、RenderTree、LayerTree。此外,还有一个临时的PaintTree;NodeTree卡片的原始节点树对应前端的Dom树,引擎会根据NodeTree来做。风格分析和布局计算;RenderTree渲染数据树,它是一棵变形的树。在许多情况下,它的树层次结构与NodeTree相同。其实我们在设计和定义引擎数据模型的时候,就讨论过要不要用这棵树,是不是一定要有这样一颗和NodeTree同级的树?最后我们还是保留了它,因为这棵树可以更灵活的调整树的关系。如果卡片分为布局阶段和渲染阶段,那么这棵树就是渲染阶段的源树。事实证明,我们的决定是正确的。我们以后支持的zindex/static能力,都是因为这棵树的存在,可以在引擎层很好的支持,而不是在平台层去模拟实现这种层级变化的能力。因此,场景支持非常有限,包括我们以后也可以从这棵树上考虑的渲染快照技术。LayerTreeLayerTree树,顾名思义,就是一种分层树。节点在RenderTree的基础上分层。同一层的节点在同一个渲染任务管线中绘制和光栅化。不同层相互独立,可以同时渲染。PaintTreePaintTree是一个临时树。严格来说,它是一个复制树。它通过RenderTree复制一个子树。每次渲染发生时临时生成。当然也会做一些节点优化处理。例如,完全覆盖的节点将被优化。调整以避免重新渲染。每一层上都有一个PaintTree,通过PaintTree进行节点绘制,生成光栅化指令或位图。高性能列表渲染对于列表中使用卡片的场景,主要考虑的是卡顿的影响,尤其是中低端设备。Cube支持异步渲染,所以在列表场景下也能流畅。同时,由于支持多线程并发,可以并发渲染多张卡片,在异步渲染的情况下不会出现明显的白屏效果。原生技术优化我们希望卡片服务于页面中区域化内容的动态展示和简单的业务逻辑,以及更多面向移动开发者的服务。尽管我们使用的卡片DSL语言描述是一种前端语言,但我们希望能够限制CSS的使用,支持有限的CSS能力,但同时我们也希望覆盖一些常用的CSS能力开发人员尽可能多。因此,我们在CSS能力方面做了专项工作,与前端团队的技术同学一起制定了魔方卡(Cube)CSS能力规范,并对CSS能力做了约束。尽管如此,在Native渲染引擎下,要很好地支持这些能力还是有很多难点,包括zindex支持,overflow等等,所以我们也基于一些依赖的平台能力进行了优化。Layercontainer我们引入Layercontainer的概念。前面介绍数据模型的时候,我们提到了LayerTree。每个Layer节点都是一个独立的渲染容器,平台View作为Layer容器渲染其他虚拟节点。如果常规做法是一个View对应一个渲染容器,我们用两个View组合成一个Layer容器(iOS用的是CALayer),把内容层和逻辑层分开。这样有很多好处,比如图层节点的阴影绘制限制裁剪问题,针对内容图层的canvascut优化等。系统。无论是Android平台还是iOS平台,系统对手势的分发和处理都有一定的限制。比如兄弟节点不能分发事件(iOS),父节点区域不能接收事件(影响溢出能力)等,所以需要修改手势。因为卡片渲染支持三方组件的扩展,为了不影响扩展组件的事件响应,我们基于Layer容器接管并改造系统的手势行为,内部管理容器节点的手势分发.组件之间的手势分布维护系统行为。光栅化立方体卡片(Cube)渲染过程包括两种渲染模式:命令渲染和位图渲染。这两种模式会在不同的场景条件下切换,以优化不同场景下的性能,例如帧率和内存。位图渲染在Android上相对复杂。默认是使用Bitmap作为离线渲染的缓存。缺点是引入了额外的cpu/gpu内存拷贝,不能充分利用GPU资源。优点是兼容性好。我们尝试过使用textureview作为离线渲染缓冲,发现6.0以下的设备存在严重的兼容性问题,不同设备的稳定性差异很大。同时光栅化能力依赖于平台系统的CanvasAPI。一些高级方法会涉及硬件加速限制,包括shadowapi和系统对glRender缓冲区(Android平台)的限制。我们还为大型画布场景执行视图分割和分段渲染。以保证渲染性能。我们还致力于用SkiaCanvasAPI替换平台层的CanvasAPI。同层渲染魔方卡(Cube)将三方组件作为一个独立的层进行数据更新,可以非常方便高效的访问扩展的三方组件。基于系统的UI能力,在卡片中统一渲染扩展组件。同时支持不同卡上元件的复用。在实际业务场景中,同层渲染也会带来很多额外的问题。地图/视频/动画等组件通常伴随着较大的性能和内存开销。这种开销会对卡片的呈现产生负面影响,尤其是在滚动列表时。对于地图/视频组件,我们与组件提供商逐案合作解决问题,并尝试在卡片上线时设置卡片点。对于动画组件,Cube继续扩展属性动画/帧动画能力,并内置画布能力。Cube现状及规划目前,Cube已服务于支付宝首页、证券(股票)、卡包、出行等20多个业务场景,日pv超过100亿。在未来相当长的一段时间内,“支付宝”内部的业务场景将逐步将现有的原生卡片、h5卡片转化为立方体。因此,一方面,我们会不断提升开发者的体验,比如开发和调试工具链;另一方面,我们会继续优化基础性能,比如追求更小的封装尺寸和更低的内存。同时,CubeBeta推出了mPaaS,供移动开发者使用。公测期间,登录mPaaS控制台,即刻赠送卡片模板十张,免费使用。>>点击这里<<体验魔方卡。卡未来规划的另一个方向是物联网设备的应用开发栈(如RTOS)。准确的说,它不是魔方卡片,而是卡片和小程序的中间形式。物联网设备的接口一般比较简单,类似于卡片;但是,它需要多个“卡片”之间的路由能力,更接近应用程序的形式。这样的混合形式既可以保留魔方卡(Cube)在内存/性能/封装体积方面的优势,又可以满足物联网设备应用开发的需求。根据我们的研究,大多数RTOS应用程序开发环境仍然停留在传统的C语言上,性能和动态性都不理想。所以对于开发者来说,Cube或许是一个不错的选择。推荐阅读:《Cube 技术解读 | 支付宝新一代动态化技术架构与选型综述》>>点这里<<体验魔方卡。