百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

用WEB技术栈开发NATIVE应用(一):WEEX SDK原理详解

ccwgpt 2024-10-11 11:21 28 浏览 0 评论

WEEX依旧采取传统的web开发技术栈进行开发,同时app在终端的运行体验不输native app。其同时解决了开发效率、发版速度以及用户体验三个核心问题。那么WEEX是如何实现的?目前WEEX已经完全开源,并捐给Apache基金会,我们可以通过分析其源码来一探究竟。

传统的移动端开发,一个完整的业务需要维护三份终端代码:Android、iOS、H5,这带来了极大的开发成本以及维护成本。尤其是对处于业务初创期需要快速试错的业务以及需要支持定期运营活动的业务。所以业界也一直在探索跨平台方案,旨在通过一套代码完成各个终端的业务逻辑。相关方案经过不断演化,从早期的H5、Hybrid到如今的Cloud Native(云原生),在开发效率和用户体验上都在一点点逼近最初的设想。

早期H5和Hybrid方案的核心是利用终端的内置浏览器(webview)功能,通过开发web应用满足跨平台需求。该方案可以解决跨平台问题,同时可以提升发版效率。但其最大的弊端在于用户体验相较于native开发的app存在较大差距,经常出现页面卡顿,加载慢等问题。

于是后来业界开始探索依旧利用web技术栈开发出媲美原生体验app的方案,于是以WEEX为代表云原生开发框架开始出现。所谓云原生(Cloud Native)指可以通过云端快速发布(与远程web应用发布流程类似),同时还可以达到媲美原生App体验的方案。WEEX依旧采取传统的web开发技术栈进行开发,同时app在终端的运行体验不输native app。其同时解决了开发效率、发版速度以及用户体验三个核心问题。那么WEEX是如何实现的?目前WEEX已经完全开源,并捐给Apache基金会,我们可以通过分析其源码来一探究竟。

WEEX框架主要分为两部分:

前端JavaScript框架

Native SDK

本文主要探讨Native SDK的核心原理,其前端JavaScript框架会在后续的文章中进行介绍。

1 整体架构

首先来看下WEEX开发的整体架构:


从上图中可以看到weex的大致工作流程:

研发人员利用web技术栈开发weex file,打包成JS Bundle,然后部署到服务器上

终端通过网络获取JS Bundle,然后在本地执行该JS Bundle

终端上提供了JS的执行引擎(JSCore)用于执行远程加载到JS Bundle

JS执行引擎执行JS Bundle,并将相关渲染指令以及其他需要利用native能力的指令通过JS-Native Bridge透出

JS-Native Bridge将渲染指令分发到native(Andorid、iOS)渲染引擎,由native渲染引擎完成最终的页面渲染

看完上述整体架构后,可以大致理解为何WEEX可以达到媲美原生的体验,因为其页面渲染并不是像H5方案一样接入浏览器的渲染能力,而是原生渲染,所以本质上渲染出来的页面就是一个native页面。

接下来我们再来将端上的模块进行详细的拆分:


如上图所示,WEEX NATIVE SDK大致可以分为如下几个层级:

JS执行层:

JS执行引擎:JSCore,解释并执行JS Bundle

main.js:提供WEEX runtime,SDK初始化,JS Core会首先加载main.js,为js bundle提供weex runtime

Bridge层:提供JS和Native的双向通信能力

Dom层:维护页面Dom结构

Render层:完成页面渲染

native组件库:本地UI组件库,每一个组件对应一个html标签,所以当我们在weex开发过程中使用到的各种标签:div、text、image等等,最终都被转化成为了一个native的控件

module manager、module库:功能模块管理层

WXSDKManger、WXSDKEngine:SDK全局环境维护

WXSDKInstance:weex 实例,一个js bundle对应一个weex实例

2 WEEX SDK初始化

有了上述大致架构和功能划分后,我们以一个实际的例子来分析WEEX NATIVE SDK的运行逻辑。首先来看下WEEX SDK在初始化阶段都做了哪些准备工作。

这里以Andorid代码为例进行分析:WEEX的初始化通常放在Application中,其初简化的初始化逻辑入如下:

public class WXApplication extends Application {

@Override

public void onCreate() {

super.onCreate();

initWeex();

......

}

private void initWeex() {

// 自定义相关配置

InitConfig config=new InitConfig.Builder()

.setImgAdapter(new ImageAdapter()) // 自定义图片适配器

.build();

WXSDKEngine.initialize(this,config);

// register module

try {

WXSDKEngine.registerModule("testmodule", TestModule.class); // 注册自定义模块

WXSDKEngine.registerModule("event", WXEventModule.class);

WXSDKEngine.registerComponent("richtext", RichText.class); // 注册自定义UI组件

......

} catch (WXException e) {

e.printStackTrace();

}

}

}

从代码中可以看到,weex的初始化比较简单,主要完成两件事:

完成初始化配置:比如指定相关适配器,比如图片请求适配器

注册自定义的UI组件和功能模块

剩下的事情都交给WEEX SDK来完成了,那么接下来就来看下WEEX SDK都做了些什么?


具体代码在WXSDKEngine.doInitInternal:

private static void doInitInternal(final Application application,final InitConfig config){

WXEnvironment.sApplication = application;

WXEnvironment.JsFrameworkInit = false;

WXBridgeManager.getInstance().post(new Runnable() {

@Override

public void run() {

long start = System.currentTimeMillis();

WXSDKManager sm = WXSDKManager.getInstance();

sm.onSDKEngineInitialize();

if(config != null ) {

sm.setInitConfig(config);

if(config.getDebugAdapter()!=null){

config.getDebugAdapter().initDebug(application);

}

}

WXSoInstallMgrSdk.init(application,

sm.getIWXSoLoaderAdapter(),

sm.getWXStatisticsListener());

boolean isSoInitSuccess = WXSoInstallMgrSdk.initSo(V8_SO_NAME, 1, config!=null?config.getUtAdapter():null);

if (!isSoInitSuccess) {

return;

}

sm.initScriptsFramework(config!=null?config.getFramework():null);

WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;

WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);

}

});

register();

}

这是WEEX SDK的初始化逻辑,其主要做了以下几件事:

初始化WXBridge,同时启动WXBridge线程,待接收指令。WXBridge在Android的实现本质上是一个基于HandlerThread的异步任务处理线程

initSo:加载so文件,即JS执行引擎

initScriptsFramework:加载SDK中的main.js,完成weex runtime的初始化

register:注册SDK自带的UI组件和功能模块

3 页面渲染

WEEX SDK在完成了初始化之后,即可开始渲染页面了。接下来我们以如下这JS代码为例,来介绍页面的渲染逻辑:


JS代码比较简单,逻辑就不介绍了。接下来重点介绍,当终端获取到如上图右侧的js bundle后,如何进行加载、渲染以及后续的相关逻辑执行。

3.1 weex实例创建

实际上当WEEX SDK获取到JS Bundle后,第一时间并不是立马渲染页面,而是先创建WEEX的实例:


这幅时序图中有两个主要逻辑:

创建createInstance:创建一个weex实例,每一个JS bundle对应一个实例,同时每一个实例都有一个instance id。由于所有的js bundle都是放入到同一个JS执行引擎中执行,那么当js执行引擎通过WXBridge将相关渲染指令传出的时候,需要通过instance id才能知道该指定要传递给哪个weex实例

execJs:在创建实例完成后,接下来才是真正将js bundle交给js执行引擎执行

3.2 页面渲染

在实例创建完成后,接下来就是页面渲染了。首先来看下页面渲染的整体流程:


js bundle涉及dom操作的执行都会被weex-vue-framework转化成native dom api, 前端框架vue是基于virtual dom api,而weex的前端框架:weex-vue-framework的核心逻辑就是将vue的virtual-dom转换成Native DOM API

weex终端的执行引擎在执行到Native DOM API后,则会将其转化为Platform API,说白了就是通过WXBridge将Native DOM API以约定的方式转发给native渲染引擎,完成页面渲染


可以看到,在js执行引擎创建好weex实例后,会执行对应的JS Bundle,并在执行到platform api的时候将其通过wxbridge,发送给DomManager。相关代码可参考:com.taobao.weex.bridge.WXBridge

3.2.1 createbody


一个页面的DOM结构最外层是body,所以创建页面一开始就是createbody,整个create body的过程大致可以分为以下几个步骤:

WXBridge将create body指令发送给WXDom模块。WXDom是另一个异步线程,负责维护页面的Dom树

WXDom创建一个新的dom树,同时创建body节点

WXDom将create body指令传递给WXRenderManager渲染引擎,渲染引擎主要完成如下几件事:

初始化一个组件实例,称为mGodComponent

generateComponentTree:由于一个WEEX页面就是由多个UI组件(Component)构成的一棵树,所以渲染引擎会初始化组件树

创建view

3.3.2 addElement


创建完body后,需要在body中添加一个text组件,指向该操作的Native DOM API为addElement,其具体操作为:

WXDomManager:更新本地dom树,添加text节点

WXRenderManager:本地渲染引擎添加相关组件:

从已注册的组件中找到text对应的组件,并实例化

将初始化完成的text组件添加到body所对应的view之上

给text组件设定布局、添加监听事件

加入数据绑定

在此一个带有一个text标签的简单页面才算是渲染完成。值得一提的是,在WXRenderManager创建组件时,需要在本地已注册的组件中需要标签对应的组件,此处标签对应的组件为com.taobao.weex.ui.component.WXText,其本质上是一个TextView。从这里可以发现,其实我们在JS Bundle中指定的各种标签,其实都最终被转化为了一个native的控件。这也就是为什么用WEEX开发出来的app,本质上还是一个Native App。

其他的对应关系还有:

div 对应WXDiv

image 对应WXImage

list对应WXListComponent

a对应WXA

……

4 总结

通过前文的介绍,相信大家对WEEX有了一个初步的系统认识。简单来说,WEEX放弃了传统的Webview,而是搭建了一个native化的浏览器,因为用native的方式实现了一个浏览器的大部分核心组成成分:

JS 执行引擎

渲染引擎

DOM树管理

网络请求,持久层存储等等能力

另外为了保证整个SDK的运行效率,SDK维护了三个线程:

bridge线程:完成js到native之间的通信

dom线程:完成dom结构的构建

渲染线程:完成UI渲染,也就是UI线程

以上就是WEEX SDK的大致框架和核心逻辑,篇幅有限,无法面面俱到

相关推荐

滨州维修服务部“一区一策”强服务

今年以来,胜利油田地面工程维修中心滨州维修服务部探索实施“一区一策”服务模式,持续拓展新技术应用场景,以优质的服务、先进的技术,助力解决管理区各类维修难题。服务部坚持问题导向,常态化对服务范围内的13...

谷歌A2A协议和MCP协议有什么区别?A2A和MCP的差异是什么?

在人工智能的快速发展中,如何实现AI模型与外部系统的高效协作成为关键问题。谷歌主导的A2A协议(Agent-to-AgentProtocol)和Anthropic公司提出的MCP协议(ModelC...

谷歌大脑用架构搜索发现更好的特征金字塔结构,超越Mask-RCNN等

【新智元导读】谷歌大脑的研究人员发表最新成果,他们采用神经结构搜索发现了一种新的特征金字塔结构NAS-FPN,可实现比MaskR-CNN、FPN、SSD更快更好的目标检测。目前用于目标检测的最先...

一文彻底搞懂谷歌的Agent2Agent(A2A)协议

前段时间,相信大家都被谷歌发布的Agent2Agent开源协议刷屏了,简称A2A。谷歌官方也表示,A2A是在MCP之后的补充,也就是MCP可以强化大模型/Agent的能力,但每个大模型/Agent互为...

谷歌提出创新神经记忆架构,突破Transformer长上下文限制

让AI模型拥有人类的记忆能力一直是学界关注的重要课题。传统的深度学习模型虽然在许多任务上取得了显著成效,但在处理需要长期记忆的任务时往往力不从心。就像人类可以轻松记住数天前看过的文章重点,但目前的...

不懂设计?AI助力,人人都能成为UI设计师!

最近公司UI资源十分紧张,急需要通过AI来解决UI人员不足问题,我在网上发现了几款AI应用非常适合用来进行UI设计。以下是一些目前非常流行且功能强大的工具,它们能够提高UI设计效率,并帮助设计师创造出...

速来!手把手教你用AI完成UI界面设计

晨星技术说晨星技术小课堂第二季谭同学-联想晨星用户体验设计师-【晨星小课堂】讲师通过简单、清晰的语言描述就能够用几十秒自动生成一组可编辑的UI界面,AIGC对于UI设计师而言已经逐步发展成了帮助我们...

「分享」一端录制,多端使用的便捷 UI 自动化测试工具,开源

一、项目介绍Recorder是一款UI录制和回归测试工具,用于录制浏览器页面UI的操作。通过UIRecorder的录制功能,可以在自测的同时,完成测试过程的录制,生成JavaScr...

APP自动化测试系列之Appium介绍及运行原理

在面试APP自动化时,有的面试官可能会问Appium的运行原理,以下介绍Appium运行原理。Appium介绍Appium概念Appium是一个开源测试自动化框架,可用于原生,混合和移动Web应用程序...

【推荐】一个基于 SpringBoot 框架开发的 OA 办公自动化系统

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍oasys是一个基于springboot框架开发的OA办公自动化系统,旨在提高组织的日常运作和管理...

自动化实践之:从UI到接口,Playwright给你全包了!

作者:京东保险宋阳1背景在车险系统中,对接保司的数量众多。每当系统有新功能迭代后,基本上各个保司的报价流程都需要进行回归测试。由于保司数量多,回归测试的场景也会变得重复而繁琐,给测试团队带来了巨大的...

销帮帮CRM移动端UI自动化测试实践:Playwright的落地与应用

实施背景销帮帮自2015年成立以来,移动端UI自动化测试的落地举步维艰,移动端的UI自动化测试一直以来都未取得良好的落地。然而移动互联网时代,怎样落地移动端的UI自动化测试以快速稳定进行移动端的端到端...

编写自动化框架不知道该如何记录日志吗?3个方法打包呈现给你。

目录结构1.loguru介绍1.1什么是日志?程序运行过程中,难免会遇到各种报错。如果这种报错是在本地发现的,你还可以进行debug。但是如果程序已经上线了,你就不能使用debug方式了...

聊聊Python自动化脚本部署服务器全流程(详细)

来源:AirPython作者:星安果1.前言大家好,我是安果!日常编写的Python自动化程序,如果在本地运行稳定后,就可以考虑将它部署到服务器,结合定时任务完全解放双手但是,由于自动化程序与平...

「干货分享」推荐5个可以让你事半功倍的Python自动化脚本

作者:俊欣来源:关于数据分析与可视化相信大家都听说自动化流水线、自动化办公等专业术语,在尽量少的人工干预的情况下,机器就可以根据固定的程序指令来完成任务,大大提高了工作效率。今天小编来为大家介绍几个P...

取消回复欢迎 发表评论: