前言
动态化跨端框架(后文统称“动态化”)是一个由京东金融大前端团队全自主研发的,一份代码,可以在HarmonyOS、iOS、Android、Web四端运行的跨平台解决方案。在研发团队使用后可大幅降低研发人力成本;为业务提供实时触达、A/B触达等能力以提升业务投放效率;同时保障了C端用户优秀的用户体验。
前言
动态化跨端框架原理介绍
① 业务层:业务代码经过打包后形成business.js发布到云端,被Harmony、iOS、Android、H5四端共用。
② 虚拟机层:虚拟机的核心职责是运行js代码,这也是跨平台框架的基础,在iOS使用系统内置的JSCore,在Android使用V8,在浏览器使用Webkit,在鸿蒙系统我们依然需要一个能够运行js代码的虚拟机。
③ 通讯层:在iOS和Android端使用了json数据格式进行通讯数据的传输,在鸿蒙系统也可以使用该方案。
④ 渲染层:使用各个系统的系统组件进行UI元素的渲染。
基于方舟虚拟机的方案探索
1、方舟字节码概念
2、在方舟虚拟机中运行JS
方舟虚拟机不能直接运行当前在V8中运行的js代码,但是能够执行方舟字节码,所以我们可以借助鸿蒙提供的工具将js代码转化为方舟字节码,这样就能利用鸿蒙系统的方舟虚拟机执行我们的js代码了。
3、存在的问题
3.1、业务无法热更新
3.2、单线程性能问题
基于V8虚拟机的方案落地
1、在V8虚拟机中运行JS
如果能把V8移植到鸿蒙系统中,我们就可以像其他两端一样使用多线程并且能实现业务热更新等特性,但是V8是一个近千万级代码的庞大仓库,需要掌握CMake、Clang、LLVM、Ninja等一系列交叉编译知识(嵌入式范畴),对于应用开发者是一个巨大的挑战,虽然我们已经掌握了V8移植到鸿蒙的技术,但从包大小、稳定性、兼容性、维护成本等维度看,华为厂商内置V8是一个具有长期收益的重大事项,通过和华为持续沟通,最终华为将V8内置到了操作系统,业界所有类动态化框均可直接使用内置V8虚拟机进行跨端框架的适配。
2、高性能核心方案
2.1、多线程架构
UI线程负责用户页面滑动、点击事件等交互行为,当发生比如用户点击事件后,同样通过接口定义的桥方法“调用JS”,将点击事件传递给JS线程进行处理,紧接着继续处理UI线程的任务,这样UI线程的交互效率就高了,充分保障了用户良好的操作体验。
//JSON描述示例
{
"type":"btn",
"value":"按钮",
"childrens":[],
"id":"238346e885ee",
"style":{
"width":"66px"
},
"attr":{
"text-color":"#FFFFFFFF"
},
"event":{
"onclick":"myclick()"
}
}
2.2、JSI技术引入
通讯桥存在的问题
动态化基于三个线程并行运行的方式,使其渲染性能已经接近于原生的渲染性能,但是在一些频繁通讯场景,通讯桥会“堵塞”,比如当业务需要监听一个页面的滑动而改变另外一个元素背景色的透明度,那么JS线程大部分时间在处理接收列表滑动距离,改变元素背景色透明度这个任务中,其他任务的执行会被严重影响。另外JSON数据传输的序列化和反序列化过程也会带来很大的线程性能损耗。
解决方案-JSI
之前使用通讯桥的一个主要原因就是 C++ 中的函数没办法完整映射到 JavaScript 中,让 JavaScript 直接调用,所以只能选择以序列化字符串的形式通过通讯桥传输。而JSI做的事情就是将 C++ 中的常用类型(函数、对象等)一一映射到 JavaScript 中,我们就能在JS中直接调用C++的函数和对象了。因为消除了桥通讯带来的序列化和异步调用的开销,大大提升了线程通讯性能。
进一步优化的方向
1、减少UI层级
当前基于多线程和JSI的架构模式在鸿蒙系统的性能还算不差,但是在鸿蒙系统上同样一个业务的UI层级是其他两端层级的约2倍。原因在于在鸿蒙系统使用系统组件进行递归渲染的时候,需要借助自定义组件进行实现,然而和iOS和Android端的命令式组件渲染不同,比如RomaDiv对应iOS就是直接翻译为UIView即可,在鸿蒙必须增加一个包裹的容器才是一个合法的自定义组件,比如Stack容器,这样每个组件的层级就多了一层,层级过多会直接影响渲染性能,在一些复杂业务场景到达一定层级后会造成页面掉帧和卡顿。
struct RomaDiv
{
build()
{
Stack(){
//借助wrapBuilder实现递归
ForEach(this.childrenTags, (childrenTag) =>
{
RomaComponentFactory.builder()//RomaComponentFactory就是对应鸿蒙系统提供的WrappedBuilder
})
}
}
}
2、降低通讯成本
当前JSI在鸿蒙系统的应用中通过JSI打通C++,再通过NAPI从C++打通ArkTS,跨语言通讯成本高。如果接入了C-API,就避免了C++和ArkTS之间类型互相转换和跨语言调用的开销,也能带来不少的性能提升。
3、JS逻辑下沉到C++
在当前架构中,JS线程运行着V-Dom树创建、对比,样式&属性解析等一系列繁重的框架逻辑,如果我们能将这些JS代码逻辑下沉到C++,框架逻辑运行效率会进一步提升。
总结
本文讲述了如何在鸿蒙系统中实现“动态化”跨端框架的高性能运行。包含探索方舟虚拟机运行方案时遇到的问题,以及基于V8虚拟机方案的具体提升手段和后续进一步提升的方案。通过阅读,你将能够更好地理解和应用这些技术,提高跨端框架的性能,提升C端用户体验。🚀