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

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

点此查看原文:https://yq.aliyun.com/article...前端

做者:阿里-移动云-大前端团队vue

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

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

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

WEEX框架主要分为两部分:前端框架

前端JavaScript框架
Native SDK服务器

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

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建立组件时,须要在本地已注册的组件中须要标签对应的组件,此处<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的原理。文章内容若有偏颇,欢迎你们指正。

相关文章
相关标签/搜索