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

简介: 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开发的整体架构:

weex1

从上图中可以看到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页面。

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

weex2

如上图所示,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都做了些什么?

weex3

具体代码在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代码为例,来介绍页面的渲染逻辑:

weex4

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

3.1 weex实例创建

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

weex5

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

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

3.2 页面渲染

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

weex6

  • 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渲染引擎,完成页面渲染

weex7

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

3.2.1 createbody

weex8

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

  • WXBridge将create body指令发送给WXDom模块。WXDom是另一个异步线程,负责维护页面的Dom树
  • WXDom创建一个新的dom树,同时创建body节点
  • WXDomcreate body指令传递给WXRenderManager渲染引擎,渲染引擎主要完成如下几件事:

    • 初始化一个组件实例,称为mGodComponent
    • generateComponentTree:由于一个WEEX页面就是由多个UI组件(Component)构成的一棵树,所以渲染引擎会初始化组件树
  • 创建view
3.3.2 addElement

weex10

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

  • WXDomManager:更新本地dom树,添加text节点
  • WXRenderManager:本地渲染引擎添加相关组件:

    • 从已注册的组件中找到text对应的组件,并实例化
    • 将初始化完成的text组件添加到body所对应的view之上
    • text组件设定布局、添加监听事件
    • 加入数据绑定

在此一个带有一个text标签的简单页面才算是渲染完成。值得一提的是,在WXRenderManager创建组件时,需要在本地已注册的组件中需要标签对应的组件,此处<text>标签对应的组件为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的大致框架和核心逻辑,篇幅有限,无法面面俱到,只是希望通过该文想大家展示WEEX基于WEB技术栈开发native app的原理。文章内容如有偏颇,欢迎大家指正。

相关文章
|
4月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
370 5
|
8月前
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!
|
8月前
|
JavaScript 前端开发 API
鸿蒙5开发宝藏案例分享---Web加载时延优化解析
本文深入解析了鸿蒙开发中Web加载完成时延的优化技巧,结合官方案例与实际代码,助你提升性能。核心内容包括:使用DevEco Profiler和DevTools定位瓶颈、四大优化方向(资源合并、接口预取、图片懒加载、任务拆解)及高频手段总结。同时提供性能优化黄金准则,如首屏资源控制在300KB内、关键接口响应≤200ms等,帮助开发者实现丝般流畅体验。
|
前端开发 JavaScript Shell
鸿蒙5开发宝藏案例分享---Web页面内点击响应时延分析
本文为鸿蒙开发者整理了Web性能优化的实战案例解析,结合官方文档深度扩展。内容涵盖点击响应时延核心指标(≤100ms)、性能分析工具链(如DevTools时间线、ArkUI Trace抓取)以及高频优化场景,包括递归函数优化、网络请求阻塞解决方案和setTimeout滥用问题等。同时提供进阶技巧,如首帧加速、透明动画陷阱规避及Web组件初始化加速,并通过优化前后Trace对比展示成果。最后总结了快速定位问题的方法与开发建议,助力开发者提升Web应用性能。
|
8月前
|
JSON 开发框架 自然语言处理
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)
本文主要介绍了应用开发中的三大核心内容:生命周期管理、资源限定与访问以及多语言支持。在生命周期部分,详细说明了应用和页面的生命周期函数及其触发时机,帮助开发者更好地掌控应用状态变化。资源限定与访问章节,则聚焦于资源限定词的定义、命名规则及匹配逻辑,并阐述了如何通过 `$r` 引用 JS 模块内的资源。最后,多语言支持部分讲解了如何通过 JSON 文件定义多语言资源,使用 `$t` 和 `$tc` 方法实现简单格式化与单复数格式化,为全球化应用提供便利。
306 104
|
8月前
|
JavaScript 前端开发 API
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(二)
本文介绍了HarmonyOS应用开发中的HML、CSS和JS语法。HML作为标记语言,支持数据绑定、事件处理、列表渲染等功能;CSS用于样式定义,涵盖尺寸单位、样式导入、选择器及伪类等特性;JS实现业务逻辑,包括ES6语法支持、对象属性、数据方法及事件处理。通过具体代码示例,详细解析了页面构建与交互的实现方式,为开发者提供全面的技术指导。
306 104
|
8月前
|
开发框架 编解码 JavaScript
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(一)
该文档详细介绍了一个兼容JS的类Web开发范式的方舟开发框架,涵盖概述、文件组织、js标签配置及app.js等内容。框架采用HML、CSS、JavaScript三段式开发方式,支持单向数据绑定,适合中小型应用开发。文件组织部分说明了目录结构、访问规则和媒体文件格式;js标签配置包括实例名称、页面路由和窗口样式信息;app.js则描述了应用生命周期与对象管理。整体内容旨在帮助开发者快速构建基于方舟框架的应用程序。
315 102
|
11月前
|
存储 人工智能 监控
大牛直播SDK在四足机器人和无人机巡检中的创新应用方案
在工业4.0和智能化浪潮下,传统巡检方式正经历深刻变革。四足机器人与无人机凭借灵活机动性和高效巡检能力崭露头角,而大牛直播SDK则赋予其实时直播与智能互动功能。本文介绍大牛直播SDK的核心优势、在四足机器人和无人机巡检中的应用方案,以及技术实现要点和未来展望,展示智能巡检的广阔前景。
339 6
|
12月前
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
756 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
监控 开发工具 Android开发
ARMS 用户体验监控正式发布原生鸿蒙应用 SDK
阿里云 ARMS 用户体验监控(RUM)推出了针对原生鸿蒙应用的 SDK。SDK 使用 ArkTS 语言开发,支持页面采集、资源加载采集、异常采集及自定义采集等功能,能够全面监控鸿蒙应用的表现。集成简单,只需几步即可将 SDK 接入项目中,为鸿蒙应用的开发者提供了强有力的支持。
722 105