Weex是如何在Android客户端上跑起来的

u=633704361,1790938583&fm=11&gp=0.jpg

参考:Weex 是如何在 iOS 客户端上跑起来的
参考:Weex SDK Android 源码解析

目录

  • Weex概述
  • Weex工作原理
  • Weex在Android上如何跑起来
  • 关于Weex,ReactNative

Weex概述

Weex非常轻量,体积小巧,语法简单,方便接入和上手。ReactNative官方只允许将ReactNative基础js库和业务JS一起打成一个JS bundle,没有提供分包的功能,所以如果想节约流量就必须制作分包打包工具。而Weex默认打的JS bundle只包含业务JS代码,体积小很多,基础JS库包含在Weex SDK中,这一点Weex与Facebook的React Native和微软的Cordova相比,Weex更加轻量,体积小巧。把Weex生成的JS bundle轻松部署到服务器端,然后Push到客户端,或者客户端请求新的资源即可完成发布。如此快速的迭代就解决了前言里面说的第一个痛点,发布无法控制时间,

Weex中Native组件和API都可以横向扩展,业务方可去中心化横向灵活化定制组件和功能模块。并且还可以直接复用Web前端的工程化管理和监控性能等工具。
知乎上有一个关于Weex 和 ReactNative很好的对比文章weex&ReactNative对比,推荐大家阅读。
Weex在2017年2月17日正式发布v0.10.0,这个里程碑的版本开始完美的兼容Vue.js开发Weex界面。
Weex又于2017年2月24 迁移至 Apache 基金会,阿里巴巴会基于 Apache 的基础设施继续迭代。并启用了全新的 GitHub 仓库:https://github.com/apache/incubator-weex
故以下源码分析都基于v0.17.0这个版本。

知乎上的对比

Weex工作原理

Weex可以通过自己设计的DSL,书写.we文件或者.vue文件来开发界面,整个页面书写分成了3段,template、style、script,借鉴了成熟的MVVM的思想。

Weex的页面结构

DOM模型

Weex页面通过类似的HTML DOM的方式管理界面。首先,页面会被分解成一个DOM树。每个DOM节点都代表了一个相对独立的native视图单元。然后不同的视图单元通过树状结构组织在一起,构成完成的页面。

Weex 在 JS 引擎中,为每个页面都提供了一套 Native DOM APIs,这套接口和 HTML DOM APIs 非常接近,利用这套接口我们可以通过 JavaScript 控制 native 的渲染逻辑。而且 Weex 上层的 Vue 2.0 也是基于这套接口进行适配的。

绝大多数情况下 JS 框架会把 Native DOM APIs 都封装好,开发者不需要直接对 Native DOM 进行操作。

  • Document 类,整个页面文档。
  • Node 类,结点的基础类。
  • Element 类,元素结点,继承自 Node,单个视图单元。
  • Comment 类,注释结点,继承自 Node,无实际意义,通常用作占位符。

每个 Weex 页面都有一个 weex.document 对象,该对象就是一个 Document 类的实例,也是下面所有接口调用的起点。

Navitve DOM API

组件

Weex 的界面就是由这些组件以 DOM 树的方式构建出来的。这些组件,原生view(Weex中的Component)与weex标签的映射。自带的组件都是通过这样的方式创建出来的。

<div></div> 对应 WXDiv

布局系统

Weex 页面中的组件会按照一定的布局规范来进行排布,我们这里提供了 CSS 中的盒模型flexbox绝对/相对/固定/吸附布局这三大块布局模型。

  • 盒模型:通过宽、高、边框、内外边距、边框等 CSS 属性描述一个组件本身的尺寸。
  • flexbox:通过 CSS 3 Flexbox 布局规范定义和描述组件之间的空间分布情况。
  • position:支持 CSS position 属性中的 absolute, relative, fixed, sticky 位置类型,其中 relative 是默认值。

功能

Weex 提供了非常丰富的系统功能 API,包括弹出存储、网络、导航、弹对话框和 toast 等,开发者可以在 Weex 页面通过获取一个 **native module **的方式引入并调用这些客户端功能 API。

上文可以知道所有的功能,都是通过module来实现的。在Js中调用。

WXStorageModule->Storage Api

生命周期

每个 Weex 页面都有其自身的生命周期,页面从开始被创建到最后被销毁,会经历到整个过程。这是通过对 Weex 页面的创建和销毁,在路由中通过 SDK 自行定义并实现的。

Weex在Android中是如何跑起来的

从.we或.vue文件到JS bundle这部分前端的代码。本文暂不涉及。

可以先通过看看.we编译后的js文件,先看看结构。更加具体的后面陆续学习后补充。

简单的.we编译后的js

//第一行,表明了编译前的文件。vue的话,则为vue
// { "framework": "Weex" }
//开始 webpackBootstrap,应该是初始化脚手架的部分。
/******/ (function(modules) { // webpackBootstrap
/******/    // The module cache
/******/    var installedModules = {};

/******/    // The require function
/******/    function __webpack_require__(moduleId) {

/******/        // Check if module is in cache
/******/        if(installedModules[moduleId])
/******/            return installedModules[moduleId].exports;

/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            exports: {},
/******/            id: moduleId,
/******/            loaded: false
/******/        };

/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/        // Flag the module as loaded
/******/        module.loaded = true;

/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }


/******/    // expose the modules object (__webpack_modules__)
/******/    __webpack_require__.m = modules;

/******/    // expose the module cache
/******/    __webpack_require__.c = installedModules;

/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "";

/******/    // Load entry module and return exports
/******/    return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
//从0这里开始,就是我们写的代码了。在0这里,获取通用的style和template
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

    var __weex_template__ = __webpack_require__(1)
    var __weex_style__ = __webpack_require__(2)

    __weex_define__('@weex-component/22de37c9919eb3fd01a7758b3c5f2baf', [], function(__weex_require__, __weex_exports__, __weex_module__) {

        __weex_module__.exports.template = __weex_template__

        __weex_module__.exports.style = __weex_style__

    })

    __weex_bootstrap__('@weex-component/22de37c9919eb3fd01a7758b3c5f2baf',undefined,undefined)

/***/ }),
  /*从1开始,就是我们自己定义的对象了。看起来像是dom 模型的json文件
  type为div的话,它对应的classlist 为container。children:标记它的子节点。
  我们看到,一个节点,对应的属性可能有 type,classlist,attr,event
  */
/* 1 */
/***/ (function(module, exports) {

    module.exports = {
      "type": "div",
      "classList": [
        "container"
      ],
      "children": [
        {
          "type": "div",
          "classList": [
            "cell"
          ],
          "children": [
            {
              "type": "image",
              "classList": [
                "thumb"
              ],
              "attr": {
                "src": ""
              }
            },
            {
              "type": "text",
              "classList": [
                "title"
              ],
              "attr": {
                "value": "Hello Weex"
              }
            }
          ]
        }
      ]
    }

/***/ }),
/* 2 */
/***/ (function(module, exports) {

    module.exports = {
      "cell": {
        "marginTop": 10,
        "marginLeft": 10
      },
      "thumb": {
        "width": 200,
        "height": 200
      },
      "title": {
        "textAlign": "center",
        "flex": 1,
        "color": "#808080"
      }
    }

/***/ })
/******/ ]);
  • 从1开始,就是我们自己定义的对象了。看起来像是dom 模型的json文件

    对于div这样的容器型组件,它可能有children属性。

    我们看到,一个节点,对应的属性可能有 type,classlist,attr,event

主要还是围绕Weex SDK的源码来进行了解。

Weex SDK初始化

先来看看playground App Android中是如何初始化的吧。

初始化是在Application中。

文件位置:incubator-weex-master/android/playground/app/src/main/java/com/alibaba/weex/WxApplication.java

public class WXApplication extends Application {

  @Override
  public void onCreate() {
    super.onCreate();

    /**
     * Set up for fresco usage.
     * Set<RequestListener> requestListeners = new HashSet<>();
     * requestListeners.add(new RequestLoggingListener());
     * ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
     *     .setRequestListeners(requestListeners)
     *     .build();
     * Fresco.initialize(this,config);
     **/
//    initDebugEnvironment(true, false, "DEBUG_SERVER_HOST");
    WXSDKEngine.addCustomOptions("appName", "WXSample");
    WXSDKEngine.addCustomOptions("appGroup", "WXApp");
    WXSDKEngine.initialize(this,
                           new InitConfig.Builder()
                               //.setImgAdapter(new FrescoImageAdapter())// use fresco adapter
                               .setImgAdapter(new ImageAdapter())
                               .setWebSocketAdapterFactory(new DefaultWebSocketAdapterFactory())
                               .setJSExceptionAdapter(new JSExceptionAdapter())
                               .setHttpAdapter(new InterceptWXHttpAdapter())
                               .build()
                          );

    WXSDKManager.getInstance().setAccessibilityRoleAdapter(new DefaultAccessibilityRoleAdapter());

    try {
      Fresco.initialize(this);
      WXSDKEngine.registerComponent("synccomponent", WXComponentSyncTest.class);
      WXSDKEngine.registerComponent(WXParallax.PARALLAX, WXParallax.class);

      WXSDKEngine.registerComponent("richtext", RichText.class);
      WXSDKEngine.registerModule("render", RenderModule.class);
      WXSDKEngine.registerModule("event", WXEventModule.class);
      WXSDKEngine.registerModule("syncTest", SyncTestModule.class);

      WXSDKEngine.registerComponent("mask",WXMask.class);
      WXSDKEngine.registerDomObject("mask", WXMaskDomObject.class);

      WXSDKEngine.registerModule("myModule", MyModule.class);
      WXSDKEngine.registerModule("geolocation", GeolocationModule.class);
      /**
       * override default image tag
       * WXSDKEngine.registerComponent("image", FrescoImageComponent.class);
       */


    } catch (WXException e) {
      e.printStackTrace();
    }

    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
      @Override
      public void onActivityCreated(Activity activity, Bundle bundle) {

      }

      @Override
      public void onActivityStarted(Activity activity) {

      }

      @Override
      public void onActivityResumed(Activity activity) {

      }

      @Override
      public void onActivityPaused(Activity activity) {

      }

      @Override
      public void onActivityStopped(Activity activity) {

      }

      @Override
      public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

      }

      @Override
      public void onActivityDestroyed(Activity activity) {
        // The demo code of calling 'notifyTrimMemory()'
        if (false) {
          // We assume that the application is on an idle time.
          WXSDKManager.getInstance().notifyTrimMemory();
        }
        // The demo code of calling 'notifySerializeCodeCache()'
        if (false) {
          WXSDKManager.getInstance().notifySerializeCodeCache();
        }
      }
    });

  }
  ...
}

初始化的代码很长,主要可以分成下面几个部分来看:

  1. WXSDKEngine.addCustomOptions("appName", "WXSample")等方法。这些个方法可以注册一些APP中的常量到js内方便调用。JS可以通过weex.config.env.appName这样的方式来调用。
  2. 通过建造者模式来创造InitConfig来初始化WxJsFramework
  3. 通过WXSDKEngine.registerComponent("richtext", RichText.class);WXSDKEngine.registerModule("render", RenderModule.class);registerDomObject()等方法来注册自定义的Component和Module。Component可以看出是Android中native控件和Wx的绑定。而Module则可以看出是非UI功能的组件和Wx的绑定。具体的这两者,放到后面再细谈。
  4. 通过registerActivityLifecycleCallbacks方法来注册得到生命周期的回调

1. 初始化配置

其实初始化的这些配置是添加到WXEnvironment类中进行管理。会在初始化JsFramework的过程中,传递给到其中。通过weex.config.env.appName这样的方式来获取。

public class WXEnvironment {

  //android os的信息
//...
  /*********************
   * Global config
   ***************************/
    
  //js lib的版本
  public static String JS_LIB_SDK_VERSION = BuildConfig.buildJavascriptFrameworkVersion;
    
  public static String WXSDK_VERSION = BuildConfig.buildVersion;
  //保存全局的Application,会在WXSDKEngine中进行初始化
  public static Application sApplication;
  //简单的获得设备的devId 通过TELEPHONY_SERVICE
  public static final String DEV_Id = getDevId();
  //虽然标注了过时的,但是默认的宽度还是750
  @Deprecated
  public static int sDefaultWidth = 750;
  //是否标记初始化完成
  public volatile static boolean JsFrameworkInit = false;

  public static final String SETTING_EXCLUDE_X86SUPPORT = "env_exclude_x86";

  public static boolean SETTING_FORCE_VERTICAL_SCREEN = false;
  /**
   * Debug model
   */
  public static boolean sDebugMode = false;
  public static boolean sForceEnableDevTool = false;
  public static String sDebugWsUrl = "";
  public static boolean sDebugServerConnectable = false;
  public static boolean sRemoteDebugMode = false;
  public static String sRemoteDebugProxyUrl = "";
  public static boolean sDebugNetworkEventReporterEnable = false;//debugtool network switch
  public static long sJSLibInitTime = 0;

  public static long sSDKInitStart = 0;// init start timestamp
  public static long sSDKInitInvokeTime = 0;//time cost to invoke init method
  public static long sSDKInitExecuteTime = 0;//time cost to execute init job
  /** from init to sdk-ready **/
  public static long sSDKInitTime =0;

  public static LogLevel sLogLevel = LogLevel.DEBUG;
  private static boolean isApkDebug = true;
  public static boolean isPerf = false;

  private static boolean openDebugLog = false;

  private static String sGlobalFontFamily;

  //自定义的一些属性是添加到这个map当中
  private static Map<String, String> options = new HashMap<>();
  static {
    options.put(WXConfig.os, OS);
    options.put(WXConfig.osName, OS);
  }

  /**
   * dynamic
   */
  public static boolean sDynamicMode = false;
  public static String sDynamicUrl = "";

  /**
   * Fetch system information.
   * @return map contains system information.
   */
  public static Map<String, String> getConfig() {
    Map<String, String> configs = new HashMap<>();
    configs.put(WXConfig.os, OS);
    configs.put(WXConfig.appVersion, getAppVersionName());
    configs.put(WXConfig.cacheDir, getAppCacheFile());
    configs.put(WXConfig.devId, DEV_Id);
    configs.put(WXConfig.sysVersion, SYS_VERSION);
    configs.put(WXConfig.sysModel, SYS_MODEL);
    configs.put(WXConfig.weexVersion, String.valueOf(WXSDK_VERSION));
    configs.put(WXConfig.logLevel,sLogLevel.getName());
    try {
      options.put(WXConfig.scale, Float.toString(sApplication.getResources().getDisplayMetrics().density));
    }catch (NullPointerException e){
      //There is little chance of NullPointerException as sApplication may be null.
      WXLogUtils.e("WXEnvironment scale Exception: ", e);
    }
    configs.putAll(options);
    if(configs!=null&&configs.get(WXConfig.appName)==null && sApplication!=null){
       configs.put(WXConfig.appName, sApplication.getPackageName());
    }
    return configs;
  }


  public static Map<String, String> getCustomOptions() {
    return options;
  }

  public static void addCustomOptions(String key, String value) {
    options.put(key, value);
  }
    //...
}

2. 初始化过程

WXSDKEngine.initialize(this, config)方法。

 public static void initialize(Application application,InitConfig config){
   //这里是先同步这个方法,方法未执行完,不会走其他被mLock锁住的方法。
   //可以看到mLock其实只是锁了一个查询初始化状态的方法
   synchronized (mLock) {
      if (mIsInit) {
        return;
      }
      long start = System.currentTimeMillis();
      WXEnvironment.sSDKInitStart = start;
     //是否可调试。可以的话。在控制台输出log
      if(WXEnvironment.isApkDebugable()){
        WXEnvironment.sLogLevel = LogLevel.DEBUG;
      }else{
        if(WXEnvironment.sApplication != null){
          WXEnvironment.sLogLevel = LogLevel.WARN;
        }else {
          WXLogUtils.e(TAG,"WXEnvironment.sApplication is " + WXEnvironment.sApplication);
        }
      }
     //进行初始化
      doInitInternal(application,config);
     //log 初始化耗时
      WXEnvironment.sSDKInitInvokeTime = System.currentTimeMillis()-start;
      WXLogUtils.renderPerformanceLog("SDKInitInvokeTime", WXEnvironment.sSDKInitInvokeTime);
      mIsInit = true;
    }
  }

进一步看,doInitInternal做了什么

private static void doInitInternal(final Application application,final InitConfig config){
  //校验Application,通过这个全局变量将application context保存到WXEnvironment中。如上面的分析所述
    WXEnvironment.sApplication = application;
    if(application == null){
      WXLogUtils.e(TAG, " doInitInternal application is null");
    }
    WXEnvironment.JsFrameworkInit = false;
  //我们这里先知道,WxBridgeManager就如他的名字一样,是js和native进行通信的一个管理者。扶着协调两者之间的通行的作用。
  //WxBridgeManager运行在一个HandlerThread(JsThread&JsHandler)中。这里就进行了异步的初始化。
    WXBridgeManager.getInstance().post(new Runnable() {
      @Override
      public void run() {
        long start = System.currentTimeMillis();
        //这里SDK manager是一个管理weex context的对象
        WXSDKManager sm = WXSDKManager.getInstance();
        //调用一个全局的回调
        sm.onSDKEngineInitialize();
        if(config != null ) {
          //将配置的参数,保存在SDK manager中
          sm.setInitConfig(config);
        }
        //初始化Android的JS引擎.
        WXSoInstallMgrSdk.init(application,
                              sm.getIWXSoLoaderAdapter(),
                              sm.getWXStatisticsListener());
        //进入这个方法,能够看到对so文件的初始化做了版本的适配。而且做了失败的重试
        boolean isSoInitSuccess = WXSoInstallMgrSdk.initSo(V8_SO_NAME, 1, config!=null?config.getUtAdapter():null);
        if (!isSoInitSuccess) {
          return;
        }
        //初始化JSFrameWork.其实就是像JSThread发送一个 INIT_FRAMEWORK的消息。然后开始初始化。初始化的过程就在JSThread中
        sm.initScriptsFramework(config!=null?config.getFramework():null);
        //最后统计时间
        WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;
        WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);
      }
    });
  //这里注册公共的组件部分
    register();
  }

doInitInternal()方法中,可以看到,初始化,其实就是干了两件事情。

  • 初始化JSFramework
  • 注册对应的native组件到JSFramework当中。
初始化JSFramework

上文调用initScriptsFramework方法,其实就是通过JsThreadhandler发送WXJSBridgeMsgType.INIT_FRAMEWORKmessage
之后会转到WxBridgeManager中的initFramework方法。

private void initFramework(String framework) {
    //这第一次一定是去加载main.js文件了。main.js文件到底是何方神圣?
    if (!isJSFrameworkInit()) {
      if (TextUtils.isEmpty(framework)) {
        // if (WXEnvironment.isApkDebugable()) {
        WXLogUtils.d("weex JS framework from assets");
        // }
        framework = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
      }
      //如果为空,则直接设置失败
      if (TextUtils.isEmpty(framework)) {
        setJSFrameworkInit(false);
        commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, "JS Framework is empty!");
        return;
      }
      try {
        if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
          WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkStart();
        }
        //下面这段是去获取crash文件
        long start = System.currentTimeMillis();
        String crashFile = "";
        try {
          crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
        } catch (Exception e) {
          e.printStackTrace();
        }
        boolean pieSupport = true;
        try {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            pieSupport = false;
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
        WXLogUtils.d("[WXBridgeManager] initFrameworkEnv crashFile:" + crashFile + " pieSupport:" + pieSupport);
        //看注释,知道开始扩展frameworkenv
        // extends initFramework.这里这个是进入native方法中
        //最新版本使用了多进程的方式来进行初始化。同样也是在native方法中完成。这儿就暂且不看了
        //这里的WxBridge就是js和native通信通道。
        //这里的assembleDefaultOptions会将WXEnvironment中的配置注入到js当中
        if (mWXBridge.initFrameworkEnv(framework, assembleDefaultOptions(), crashFile, pieSupport) == INIT_FRAMEWORK_OK) {
          WXEnvironment.sJSLibInitTime = System.currentTimeMillis() - start;
          WXLogUtils.renderPerformanceLog("initFramework", WXEnvironment.sJSLibInitTime);
          WXEnvironment.sSDKInitTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
          WXLogUtils.renderPerformanceLog("SDKInitTime", WXEnvironment.sSDKInitTime);
          //这里还没报错,那就算是初始化完成了。
          setJSFrameworkInit(true);

          if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
            WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkReady();
          }
        //这里先将失败的任务重新添加回来
          execRegisterFailTask();
          WXEnvironment.JsFrameworkInit = true;
          //重新注册。最后通过jsThread中JsBridge通过execJS系列native方法重新注册
          registerDomModule();
          String reinitInfo = "";
          if (reInitCount > 1) {
            reinitInfo = "reinit Framework:";
          }
          commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_SUCCESS, reinitInfo + "success");
        } else {
          if (reInitCount > 1) {
            WXLogUtils.e("[WXBridgeManager] invokeReInitFramework  ExecuteJavaScript fail");
            String err = "[WXBridgeManager] invokeReInitFramework  ExecuteJavaScript fail reinit FrameWork";
            commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_REINIT_FRAMEWORK, err);
          } else {
            WXLogUtils.e("[WXBridgeManager] invokeInitFramework  ExecuteJavaScript fail");
            String err = "[WXBridgeManager] invokeInitFramework  ExecuteJavaScript fail";
            commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, err);
          }
        }
      } catch (Throwable e) {
        if (reInitCount > 1) {
          WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
          String err = "[WXBridgeManager] invokeInitFramework reinit FrameWork exception!#" + e.toString();
          commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_REINIT_FRAMEWORK, err);
        } else {
          WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
          String err = "[WXBridgeManager] invokeInitFramework exception!#" + e.toString();
          commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, err);
        }
      }

    }
  }
加载本地的main.js

第一次下载完源码。搜索全局。会发现发现找不到main.js这样的文件。其实他是SDK自带的。它是由gradle从中,加载 incubator-weex\pre-build\native-bundle-main.js文件生成的。直接打开这个文件会看到一堆经过webpack压缩之后的文件

下面这个源文件的路径。已经在github上找不到了。

这个文件的源文件在https://github.com/apache/incubator-weex/tree/master/html5目录下。对应的入口文件是 html5/render/native/index.js

简单的看一下gradle文件的配置

incubator-weex\android\sdk\build.gradle

android{  
  ...    
   //将文件从prebuild目录中复制到assets目录下,并重命名    
   copy {        
     from '../../pre-build'        
     into new File(projectDir,"assets")       
     include 'native-bundle-main.js'        
     rename('native-bundle-main.js','main.js')    
   }    
    //从这个文件中,得到 buildJavascriptFrameworkVersion 的版本号    
    def line    
    new File(projectDir,"assets/main.js").withReader { line = it.readLine() }    
    def m = line =~ /[A-Z\s]+\s+([0-9\.]+),\s+Build\s+[0-9]+/;    
    def jsfmVersion = m[0][1]    
    println jsfmVersion  
    ...
}
assembleDefaultOptions()方法
private WXParams assembleDefaultOptions() {
  //通过Environment的getConfig方法,就对应的配置输入到config的map中
    Map<String, String> config = WXEnvironment.getConfig();
  //再通过WXParams这个对象,传递给JsFrameworks当中
    WXParams wxParams = new WXParams();
    wxParams.setPlatform(config.get(WXConfig.os));
    wxParams.setCacheDir(config.get(WXConfig.cacheDir));
    wxParams.setOsVersion(config.get(WXConfig.sysVersion));
    wxParams.setAppVersion(config.get(WXConfig.appVersion));
    wxParams.setWeexVersion(config.get(WXConfig.weexVersion));
    wxParams.setDeviceModel(config.get(WXConfig.sysModel));
    wxParams.setShouldInfoCollect(config.get("infoCollect"));
    wxParams.setLogLevel(config.get(WXConfig.logLevel));
    String appName = config.get(WXConfig.appName);
    if (!TextUtils.isEmpty(appName)) {
      wxParams.setAppName(appName);
    }
    //这里指的注意的是设置了deivceWidth。这里需要注意的是,如果没有手动设置这个值,其实是会同个这个utils中去获取。而这个WXViewUtils其实得到整个屏幕宽度
    wxParams.setDeviceWidth(TextUtils.isEmpty(config.get("deviceWidth")) ? String.valueOf(WXViewUtils.getScreenWidth(WXEnvironment.sApplication)) : config.get("deviceWidth"));
    wxParams.setDeviceHeight(TextUtils.isEmpty(config.get("deviceHeight")) ? String.valueOf(WXViewUtils.getScreenHeight(WXEnvironment.sApplication)) : config.get("deviceHeight"));
   //这里讲所有自定额的Options设置
    wxParams.setOptions(WXEnvironment.getCustomOptions());
    //是否需要初始化v8
    wxParams.setNeedInitV8(WXSDKManager.getInstance().needInitV8());
    mInitParams = wxParams;
    return wxParams;
  }

WXViewUtils

public static int getScreenWidth(Context ctx) {
    if(ctx!=null){
      Resources res = ctx.getResources();
      //获取屏幕的宽度像素
      mScreenWidth = res.getDisplayMetrics().widthPixels;
      if(WXEnvironment.SETTING_FORCE_VERTICAL_SCREEN){
        mScreenHeight = res
                .getDisplayMetrics()
                .heightPixels;
        mScreenWidth = mScreenHeight > mScreenWidth ? mScreenWidth : mScreenHeight;
      }
    } else if(WXEnvironment.isApkDebugable()){
      throw new WXRuntimeException("Error Context is null When getScreenHeight");
    }
    return mScreenWidth;
  }
注册对应的native组件到JSFramework当中

回到WXSDKEngine中的doInitInternal()方法的最后的register()方法。由这个方法进行注册相应的组件。

private static void register() {
    //这个batchOperationHelper是一个注册组件的intercepter
    //创建这个类。之后registerXX就会添加到注册队列中。最后再通过flush()将其一次性执行
    BatchOperationHelper batchHelper = new BatchOperationHelper(WXBridgeManager.getInstance());
    //下面开始批量注册SDK自带的组件
    try {
      registerComponent(
        new SimpleComponentHolder(
          WXText.class,
          new WXText.Creator()
        ),
        false,
        WXBasicComponentType.TEXT
      );
      registerComponent(
        new SimpleComponentHolder(
          WXDiv.class,
          new WXDiv.Ceator()
        ),
        false,
        WXBasicComponentType.CONTAINER,
        WXBasicComponentType.DIV,
        WXBasicComponentType.HEADER,
        WXBasicComponentType.FOOTER
      );
      registerComponent(
        new SimpleComponentHolder(
          WXImage.class,
          new WXImage.Ceator()
        ),
        false,
        WXBasicComponentType.IMAGE,
        WXBasicComponentType.IMG
      );
      registerComponent(
        new SimpleComponentHolder(
          WXScroller.class,
          new WXScroller.Creator()
        ),
        false,
        WXBasicComponentType.SCROLLER
      );
      registerComponent(
        new SimpleComponentHolder(
          WXSlider.class,
          new WXSlider.Creator()
        ),
        true,
        WXBasicComponentType.SLIDER,
        WXBasicComponentType.CYCLE_SLIDER
      );
      registerComponent(
        new SimpleComponentHolder(
                WXSliderNeighbor.class,
          new WXSliderNeighbor.Creator()
        ),
        true,
        WXBasicComponentType.SLIDER_NEIGHBOR
      );
      String simpleList = "simplelist";
      registerComponent(SimpleListComponent.class,false,simpleList);
      registerComponent(WXListComponent.class, false,WXBasicComponentType.LIST,WXBasicComponentType.VLIST,WXBasicComponentType.RECYCLER,WXBasicComponentType.WATERFALL);
      registerComponent(WXRecyclerTemplateList.class, false,WXBasicComponentType.RECYCLE_LIST);
      registerComponent(HorizontalListComponent.class,false,WXBasicComponentType.HLIST);
      registerComponent(WXBasicComponentType.CELL, WXCell.class, true);
      registerComponent(WXBasicComponentType.CELL_SLOT, WXCell.class, true);
      registerComponent(WXBasicComponentType.INDICATOR, WXIndicator.class, true);
      registerComponent(WXBasicComponentType.VIDEO, WXVideo.class, false);
      registerComponent(WXBasicComponentType.INPUT, WXInput.class, false);
      registerComponent(WXBasicComponentType.TEXTAREA, Textarea.class,false);
      registerComponent(WXBasicComponentType.SWITCH, WXSwitch.class, false);
      registerComponent(WXBasicComponentType.A, WXA.class, false);
      registerComponent(WXBasicComponentType.EMBED, WXEmbed.class, true);
      registerComponent(WXBasicComponentType.WEB, WXWeb.class);
      registerComponent(WXBasicComponentType.REFRESH, WXRefresh.class);
      registerComponent(WXBasicComponentType.LOADING, WXLoading.class);
      registerComponent(WXBasicComponentType.LOADING_INDICATOR, WXLoadingIndicator.class);
      registerComponent(WXBasicComponentType.HEADER, WXHeader.class);

      registerModule("modal", WXModalUIModule.class, false);
      registerModule("instanceWrap", WXInstanceWrap.class, true);
      registerModule("animation", WXAnimationModule.class, true);
      registerModule("webview", WXWebViewModule.class, true);
      registerModule("navigator", WXNavigatorModule.class);
      registerModule("stream", WXStreamModule.class);
      registerModule("timer", WXTimerModule.class, false);
      registerModule("storage", WXStorageModule.class, true);
      registerModule("clipboard", WXClipboardModule.class, true);
      registerModule("globalEvent",WXGlobalEventModule.class);
      registerModule("picker", WXPickersModule.class);
      registerModule("meta", WXMetaModule.class,true);
      registerModule("webSocket", WebSocketModule.class);
      registerModule("locale", WXLocaleModule.class);


      registerDomObject(simpleList, WXListDomObject.class);
      registerDomObject(WXBasicComponentType.INDICATOR, WXIndicator.IndicatorDomNode.class);
      registerDomObject(WXBasicComponentType.TEXT, WXTextDomObject.class);
      registerDomObject(WXBasicComponentType.HEADER, WXCellDomObject.class);
      registerDomObject(WXBasicComponentType.CELL, WXCellDomObject.class);
      registerDomObject(WXBasicComponentType.CELL_SLOT, WXCellDomObject.class);
      registerDomObject(WXBasicComponentType.INPUT, BasicEditTextDomObject.class);
      registerDomObject(WXBasicComponentType.TEXTAREA, TextAreaEditTextDomObject.class);
      registerDomObject(WXBasicComponentType.SWITCH, WXSwitchDomObject.class);
      registerDomObject(WXBasicComponentType.LIST, WXListDomObject.class);
      registerDomObject(WXBasicComponentType.RECYCLE_LIST, WXRecyclerDomObject.class);
      registerDomObject(WXBasicComponentType.VLIST, WXListDomObject.class);
      registerDomObject(WXBasicComponentType.HLIST, WXListDomObject.class);
      registerDomObject(WXBasicComponentType.SCROLLER, WXScrollerDomObject.class);
      registerDomObject(WXBasicComponentType.RECYCLER, WXRecyclerDomObject.class);
      registerDomObject(WXBasicComponentType.WATERFALL, WXRecyclerDomObject.class);
    } catch (WXException e) {
      WXLogUtils.e("[WXSDKEngine] register:", e);
    }
    batchHelper.flush();
  }

在WXSDKEngine初始化的时候就分别注册了这三样东西,Components,Modules,DomObjects。

Components的注册过程
     
registerComponent(
        new SimpleComponentHolder(
          WXText.class,
          new WXText.Creator()
        ),
        false,
        WXBasicComponentType.TEXT
      );
      registerComponent(
        new SimpleComponentHolder(
          WXDiv.class,
          new WXDiv.Ceator()
        ),
        false,
        WXBasicComponentType.CONTAINER,
        WXBasicComponentType.DIV,
        WXBasicComponentType.HEADER,
        WXBasicComponentType.FOOTER
      );
      registerComponent(
        new SimpleComponentHolder(
          WXImage.class,
          new WXImage.Ceator()
        ),
        false,
        WXBasicComponentType.IMAGE,
        WXBasicComponentType.IMG
      );
      registerComponent(
        new SimpleComponentHolder(
          WXScroller.class,
          new WXScroller.Creator()
        ),
        false,
        WXBasicComponentType.SCROLLER
      );
      registerComponent(
        new SimpleComponentHolder(
          WXSlider.class,
          new WXSlider.Creator()
        ),
        true,
        WXBasicComponentType.SLIDER,
        WXBasicComponentType.CYCLE_SLIDER
      );
      registerComponent(
        new SimpleComponentHolder(
                WXSliderNeighbor.class,
          new WXSliderNeighbor.Creator()
        ),
        true,
        WXBasicComponentType.SLIDER_NEIGHBOR
      );
      String simpleList = "simplelist";
      registerComponent(SimpleListComponent.class,false,simpleList);
      registerComponent(WXListComponent.class, false,WXBasicComponentType.LIST,WXBasicComponentType.VLIST,WXBasicComponentType.RECYCLER,WXBasicComponentType.WATERFALL);
      registerComponent(WXRecyclerTemplateList.class, false,WXBasicComponentType.RECYCLE_LIST);
      registerComponent(HorizontalListComponent.class,false,WXBasicComponentType.HLIST);
      registerComponent(WXBasicComponentType.CELL, WXCell.class, true);
      registerComponent(WXBasicComponentType.CELL_SLOT, WXCell.class, true);
      registerComponent(WXBasicComponentType.INDICATOR, WXIndicator.class, true);
      registerComponent(WXBasicComponentType.VIDEO, WXVideo.class, false);
      registerComponent(WXBasicComponentType.INPUT, WXInput.class, false);
      registerComponent(WXBasicComponentType.TEXTAREA, Textarea.class,false);
      registerComponent(WXBasicComponentType.SWITCH, WXSwitch.class, false);
      registerComponent(WXBasicComponentType.A, WXA.class, false);
      registerComponent(WXBasicComponentType.EMBED, WXEmbed.class, true);
      registerComponent(WXBasicComponentType.WEB, WXWeb.class);
      registerComponent(WXBasicComponentType.REFRESH, WXRefresh.class);
      registerComponent(WXBasicComponentType.LOADING, WXLoading.class);
      registerComponent(WXBasicComponentType.LOADING_INDICATOR, WXLoadingIndicator.class);
      registerComponent(WXBasicComponentType.HEADER, WXHeader.class);

这里提供了27种默认的基础组件。

这里有两种签名registerComponent()进行注册,最后会调用的还是WXComponentRegistry这个类的方法。(这里我们先知道WXComponentRegistry是管理所有注册组件的类。)

  /**
   * 从这方法的签名可以看到。通过这个类来注册Component组件
   * @param type String类型的字符串。定义这个组件调用的名称
   * @param holder IFComponentHolder的缓存类,作用如它的名字,就是Holder。判断是否赖加载。和存储对应的键值对。一般通过默认SimpleComponentHolder来进行设置
   * @param componentInfo 存储component的字典。hashMap
   * @return
   * @throws WXException
   */
public static boolean registerComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) throws WXException {
    if (holder == null || TextUtils.isEmpty(type)) {
      return false;
    }

  //在jsThread中执行,确保注册的和调用的是在同一个线程?
    //execute task in js thread to make sure register order is same as the order invoke register method.
    WXBridgeManager.getInstance()
        .post(new Runnable() {
      @Override
      public void run() {
        try {
          Map<String, Object> registerInfo = componentInfo;
          if (registerInfo == null){
            registerInfo = new HashMap<>();
          }
        //这个ComponentInfo的map中存储了type,methods两个变量。
          //这里需要记住的是,还存放这之前的 append 属性。
          registerInfo.put("type",type);
          registerInfo.put("methods",holder.getMethods());
          //分别向native和js进行注册
          registerNativeComponent(type, holder);
          registerJSComponent(registerInfo);
          //注册成功后,进行缓存,加入ComponentInfos的map中。
          sComponentInfos.add(registerInfo);
        } catch (WXException e) {
          WXLogUtils.e("register component error:", e);
        }

      }
    });
    return true;
  }

可以看到,SDK通过WXComponentRegistry来分别向native和js进行注册,成功后并对其进行缓存。提供效率。

  • IFComponentHolder

    还是先看一下IFComponentHolder这个缓存类。再看相应的注册方法。这个类的默认实现是SimpleComponentHolder

    public class SimpleComponentHolder implements IFComponentHolder{
      public static final String TAG = "SimpleComponentHolder";
      private final Class<? extends WXComponent> mClz;
      //缓存有方法和属性的调用map.Invoker是一个方法的接口。它包括三个方法,分别为调用方法,获取方法参数的类型和确定是否在uiThread中调用方法
      private Map<String, Invoker> mPropertyInvokers;
      private Map<String, Invoker> mMethodInvokers;
      //这个Creator来创建Component对象
      private ComponentCreator mCreator;
      
      //使用默认实现的classComponentCreator
      public SimpleComponentHolder(Class<? extends WXComponent> clz) {
        this(clz,new ClazzComponentCreator(clz));
      }
    
      public SimpleComponentHolder(Class<? extends WXComponent> clz,ComponentCreator customCreator) {
        this.mClz = clz;
        this.mCreator = customCreator;
      }
    
      //通过Component注解来判断是否是懒加载。如果不是,则注册时调用generate直接生成
      @Override
      public void loadIfNonLazy() {
        Annotation[] annotations = mClz.getDeclaredAnnotations();
        for (Annotation annotation :
          annotations) {
          //懒加载是通过Component这个注解
          if (annotation instanceof Component){
            if(!((Component) annotation).lazyload() && mMethodInvokers == null){
              generate();
            }
            return;
          }
        }
      }
    
      private synchronized void generate(){
        if(WXEnvironment.isApkDebugable()) {
          WXLogUtils.d(TAG, "Generate Component:" + mClz.getSimpleName());
        }
    
        Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = getMethods(mClz);
        mPropertyInvokers = methodPair.first;
        mMethodInvokers = methodPair.second;
      }
    
      //通过解析类中的注解和方法,返回对应的属性和方法的invoker map
      static Pair<Map<String,Invoker>,Map<String,Invoker>> getMethods(Class clz){
        //methods是存放属性调用的map.invokers是存放方法调用的map
        Map<String, Invoker> methods = new HashMap<>();
        Map<String, Invoker> mInvokers = new HashMap<>();
    
        Annotation[] annotations;
        Annotation anno;
        try {
          //获取所有的方法
          for (Method method : clz.getMethods()) {
            try {
              //获取方法的注解
              annotations = method.getDeclaredAnnotations();
              for (int i = 0, annotationsCount = annotations.length;
                   i < annotationsCount; ++i) {
                anno = annotations[i];
                if(anno == null){
                  continue;
                }
                //如果是被 WXComponentProp 注解,则表示这个是属性,则创建调用的MethodInvoker加入map中。
                if (anno instanceof WXComponentProp) {
                  String name = ((WXComponentProp) anno).name();
                  methods.put(name, new MethodInvoker(method,true));
                  break;
                }else if(anno instanceof JSMethod){
                  //如果是JsMethod注解,则表示这个是一个方法。获取是否别名。同样构造方法放入方法的map中
                  JSMethod methodAnno = (JSMethod)anno;
                  String name = methodAnno.alias();
                  if(JSMethod.NOT_SET.equals(name)){
                    name = method.getName();
                  }
                  mInvokers.put(name, new MethodInvoker(method,methodAnno.uiThread()));
                  break;
                }
              }
            } catch (ArrayIndexOutOfBoundsException | IncompatibleClassChangeError e) {
              //ignore: getDeclaredAnnotations may throw this
            }
          }
        }catch (IndexOutOfBoundsException e){
          e.printStackTrace();
          //ignore: getMethods may throw this
        }
        return new Pair<>(methods,mInvokers);
      }
      /*
    构造WXComponent实例,并且绑定当前的holder
     */
    @Override
    public synchronized WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException {
      WXComponent component = mCreator.createInstance(instance,node,parent);
    
      component.bindHolder(this);
      return component;
    }
    /* 
      获取property invoker,如果是懒加载的话,则开始生成
    */
    @Override
    public synchronized Invoker getPropertyInvoker(String name){
        if (mPropertyInvokers == null) {
          generate();
        }
    
      return mPropertyInvokers.get(name);
    } 
    /*  
       获取method invoker,如果是懒加载的话,则开始生成
    */
    @Override
    public Invoker getMethodInvoker(String name) {
      if(mMethodInvokers == null){
        generate();
      }
      return mMethodInvokers.get(name);
    }
    
    @Override
    public String[] getMethods() {
      if(mMethodInvokers == null){
        generate();
      }
      Set<String> keys = mMethodInvokers.keySet();
      return keys.toArray(new String[keys.size()]);
    }
    }  
    

    其中包括 了一个默认实现的Creator

     /*
        默认实现由一个ClaszzComponentCreator。这个Creator是用来给遵循sdk自带的构造方法的Component提供的默认实现。其中兼容了3-5的构造方法
         */
        static class ClazzComponentCreator implements ComponentCreator{
    
          private Constructor<? extends WXComponent> mConstructor;
          private final Class<? extends WXComponent> mCompClz;
    
          ClazzComponentCreator(Class<? extends WXComponent> c){
            mCompClz = c;
          }
    
          private void loadConstructor(){
            Class<? extends WXComponent> c = mCompClz;
            Constructor<? extends WXComponent> constructor;
            try {
              constructor = c.getConstructor(WXSDKInstance.class, WXDomObject.class, WXVContainer.class);
            } catch (NoSuchMethodException e) {
              WXLogUtils.d("ClazzComponentCreator","Use deprecated component constructor");
              try {
                //compatible deprecated constructor with 4 args
                constructor = c.getConstructor(WXSDKInstance.class, WXDomObject.class, WXVContainer.class, boolean.class);
              } catch (NoSuchMethodException e1) {
                try {
                  //compatible deprecated constructor with 5 args
                  constructor = c.getConstructor(WXSDKInstance.class, WXDomObject.class, WXVContainer.class,String.class, boolean.class);
                } catch (NoSuchMethodException e2) {
                  throw new WXRuntimeException("Can't find constructor of component.");
                }
              }
            }
            mConstructor = constructor;
          }
    
          @Override
          public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException {
            if(mConstructor == null){
              loadConstructor();
            }
            int parameters = mConstructor.getParameterTypes().length;
            WXComponent component;
    
            if(parameters == 3){
              //这个构造方法是自动生成instanceId和默认懒加载false.懒加载的flag判断,定义在了自定义注解里面了。
              component =  mConstructor.newInstance(instance,node,parent);
            }else if(parameters == 4){
              //这个是自动生成instanceId
              component =  mConstructor.newInstance(instance,node,parent,false);
            }else{
              //compatible deprecated constructor
              //这个是兼容过时的构造器。在构造方法中定义instanceId和默认懒加载flag
              component =  mConstructor.newInstance(instance,node,parent,instance.getInstanceId(),parent.isLazy());
            }
            return component;
          }
        }
    
  • registerNativeComponent

    接下来看看,向native是如何注册这个Component的

    
      private static boolean registerNativeComponent(String type, IFComponentHolder holder) throws WXException {
        try {
          //判断是否是懒加载,如上面方法分析过,如果不是懒加载,则直接反射生成属性和方法的map
          holder.loadIfNonLazy();
          //放入TypeComponentMap中
          sTypeComponentMap.put(type, holder);
        }catch (ArrayStoreException e){
          e.printStackTrace();
          //ignore: ArrayStoreException: java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
        }
        return true;
      }
    
  • registerJsComponent

      private static boolean registerJSComponent(Map<String, Object> componentInfo) throws WXException {
        ArrayList<Map<String, Object>> coms = new ArrayList<>();
        coms.add(componentInfo);
        //通过WxSDKManager注册这个Components
        WXSDKManager.getInstance().registerComponents(coms);
        return true;
      }
    

    通过WXSDKManager,最后转发到了WxBridgeManager中的invokeRegisterComponents方法

     private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {
       //错误的列表不能等于源列表
        if (components == failReceiver) {
          throw new RuntimeException("Fail receiver should not use source.");
        }
       //如果注册时js还未初始化,则会加入错误的列表中,等待初始化后进行加载
        if (!isJSFrameworkInit()) {
          WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");
    
          for (Map<String, Object> comp : components) {
            failReceiver.add(comp);
          }
          return;
        }
        if (components == null) {
          return;
        }
      //转成WXJSObject对象数组。这个WXJsObject就是与JsFramework通行的实体。
       //WxJsonUtils中通过fastJson将map转成json结构
        WXJSObject[] args = {new WXJSObject(WXJSObject.JSON,
            WXJsonUtils.fromObjectToJSONString(components))};
        try {
          //通过WxBridge进行通行,执行js代码。注入到js框架中。
          mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args);
        } catch (Throwable e) {
          WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", e);
        WXExceptionUtils.commitCriticalExceptionRT(null,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorCode(),
                METHOD_REGISTER_COMPONENTS,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorMsg()
                        + args.toString()
                        + WXLogUtils.getStackTrace(e),
                null);
        }
      }
    
    

    这样这个Components就在WXComponentRegistry中注册完成了。等待调用。

modules的注册过程

和Component的注册过程类似。modules的注册,最后是转到了WXModuleManager中的registerModule方法中进行。

 /**
   *
   * @param moduleName module的名称
   * @param factory 生成ModuleFactory 其中提供了TypeModuleFactory这个默认实现的工厂类
   * @param global 是否全局的module。就会去放入全局的缓存当中
   * @return
   * @throws WXException
   */
public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException {
    if (moduleName == null || factory == null) {
      return false;
    }
    //这里需要注意的module的名字是dom的字样。应该是和内置的dom冲突了?
    if (TextUtils.equals(moduleName,WXDomModule.WXDOM)) {
      WXLogUtils.e("Cannot registered module with name 'dom'.");
      return false;
    }

    //和Component相同的套路。
    //execute task in js thread to make sure register order is same as the order invoke register method.
    WXBridgeManager.getInstance()
        .post(new Runnable() {
      @Override
      public void run() {
        if (sModuleFactoryMap.containsKey(moduleName)) {
          WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
        }
        //可以看到这个global flag的作用。就是是否在全局缓存这个module.
        if (global) {
          //如果是全局缓存的话,则马上构造,并且放入map当中
          try {
            WXModule wxModule = factory.buildInstance();
            wxModule.setModuleName(moduleName);
            sGlobalModuleMap.put(moduleName, wxModule);
          } catch (Exception e) {
            WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
          }
        }
        //同样需要向native和js中分别注册module
        try {
          registerNativeModule(moduleName, factory);
        } catch (WXException e) {
          WXLogUtils.e("", e);
        }
        registerJSModule(moduleName, factory);
      }
    });
    return true;
  }
  • ModuleFactory

    按照Component养成的惯例,还是先来看看默认实现类TypeModuleFactory

    public class TypeModuleFactory<T extends WXModule> implements ModuleFactory<T> {
      public static final String TAG = "TypeModuleFactory";
      //对比Component这里就直接缓存Class类就可以了。应该没有对应的构造方法需要规定
      Class<T> mClazz;
      //缓存这个类的方法
      Map<String, Invoker> mMethodMap;
    
      public TypeModuleFactory(Class<T> clz) {
        mClazz = clz;
      }
    
      //生成方法
      private void generateMethodMap() {
        if(WXEnvironment.isApkDebugable()) {
          WXLogUtils.d(TAG, "extractMethodNames:" + mClazz.getSimpleName());
        }
        HashMap<String, Invoker> methodMap = new HashMap<>();
        try {
          //同样是开始遍历
          for (Method method : mClazz.getMethods()) {
            // iterates all the annotations available in the method
            for (Annotation anno : method.getDeclaredAnnotations()) {
              if (anno != null) {
                //这里是同样是通过JsMethod这个注解来标记方法。同时设置是否uiThread执行的
                if(anno instanceof JSMethod) {
                  JSMethod methodAnnotation = (JSMethod) anno;
                  String name = JSMethod.NOT_SET.equals(methodAnnotation.alias())? method.getName():methodAnnotation.alias();
                  methodMap.put(name, new MethodInvoker(method, methodAnnotation.uiThread()));
                  break;
                }else if(anno instanceof WXModuleAnno) {
                  //WxModuleAnno这个注解来标注。这个注解等同于JsMethod.现在已经过时了。
                  WXModuleAnno methodAnnotation = (WXModuleAnno)anno;
                  methodMap.put(method.getName(), new MethodInvoker(method,methodAnnotation.runOnUIThread()));
                  break;
                }
              }
            }
          }
        } catch (Throwable e) {
          WXLogUtils.e("[WXModuleManager] extractMethodNames:", e);
        }
        mMethodMap = methodMap;
      }
      
      //构造实例
       @Override
      public T buildInstance() throws IllegalAccessException, InstantiationException {
        return mClazz.newInstance();
      }
    
      //如果不是global的方法,则从这儿开始反射得到所有的方法
      @Override
      public String[] getMethods() {
        if (mMethodMap == null) {
          generateMethodMap();
        }
        Set<String> keys = mMethodMap.keySet();
        return keys.toArray(new String[keys.size()]);
      }
    
      @Override
      public Invoker getMethodInvoker(String name) {
        if (mMethodMap == null) {
          generateMethodMap();
        }
        return mMethodMap.get(name);
      }
    }
    
  • registerNativeModule()

    //相同的套路。native注册,就是moduleFactory缓存到全局的map当中
      static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException {
        if (factory == null) {
          return false;
        }
    
        try {
          sModuleFactoryMap.put(moduleName, factory);
        }catch (ArrayStoreException e){
          e.printStackTrace();
          //ignore:
          //may throw this exception:
          //java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
        }
        return true;
      }
    

  • registerJsModule()

    //js注册,同样是通过WxSDKManager转发到WxBridgeManager中进行注册 
    static boolean registerJSModule(String moduleName, ModuleFactory factory) {
        Map<String, Object> modules = new HashMap<>();
        modules.put(moduleName, factory.getMethods());
        WXSDKManager.getInstance().registerModules(modules);
        return true;
      }
    

    WXBridgeManager中进行注册

     private void invokeRegisterModules(Map<String, Object> modules, List<Map<String, Object>> failReceiver) {
        if (modules == null || !isJSFrameworkInit()) {
          if (!isJSFrameworkInit()) {
            WXLogUtils.d("[WXinvokeRegisterModulesBridgeManager] invokeRegisterModules: framework.js uninitialized.");
          }
          failReceiver.add(modules);
          return;
        }
    
        WXJSObject[] args = {new WXJSObject(WXJSObject.JSON,
            WXJsonUtils.fromObjectToJSONString(modules))};
        try {
          mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args);
        } catch (Throwable e) {
        WXExceptionUtils.commitCriticalExceptionRT(null,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorCode(),
                "invokeRegisterModules", WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +
                " \n " + e.getMessage() + modules.entrySet().toString(),
                null );
    
          WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", e);
        }
      }
    
DomObject的注册过程
  • 什么是WXDomObject

    更具注释的介绍,我们知道这类只包含所有所有节点的信息。包括style, attribute and event。它只包含了dom的信息,不包括如何去渲染。

    实际上,每一个Component持有一个androidview的实例和WXDomObject的实例。

基本上是相同的套路。最后是在WXDomRegistry注册。注册的过程更为简单,只是将class换成起来。

public class WXDomRegistry {

  public static Class<? extends WXDomObject> mDefaultClass = WXDomObject.class;
  private static Map<String, Class<? extends WXDomObject>> sDom = new HashMap<>();

  public static boolean registerDomObject(String type, Class<? extends WXDomObject> clazz) throws WXException {
    if (clazz == null || TextUtils.isEmpty(type)) {
      return false;
    }

    if (sDom.containsKey(type)) {
      if (WXEnvironment.isApkDebugable()) {
        throw new WXException("WXDomRegistry had duplicate Dom:" + type);
      } else {
        WXLogUtils.e("WXDomRegistry had duplicate Dom: " + type);
        return false;
      }
    }
    sDom.put(type, clazz);
    return true;
  }

  public static Class<? extends WXDomObject> getDomObjectClass(String type) {
    if (TextUtils.isEmpty(type)) {
      return mDefaultClass;
    }
    Class<? extends WXDomObject> clazz = sDom.get(type);
    return clazz == null ? mDefaultClass : clazz;
  }
}

到这里,就完成了WXSDKEngine的默认的初始化过程了

3. 初始化自定义组件

通过和上述相同的方式,自定义组件的注册的方式和上面相同。

Weex 是如何让JS调起原生View

上一章节我们分析了WXSDKEngine是如何初始化的,那么初始化完成之后,Android Native客户端是如何接收到JS的页面并生成View的呢?这一章节我们来分析分析。

进入到IndexActivity中,在onCreate()方法中调用super.onCreate()方法中进行初始化,并且render()这样的方法。其实是来到了WXSDKInstance中的对应方法。

WXSDKInstance

初始化
  protected void createWeexInstance(){
    destoryWeexInstance();
    //这两行代码其实没啥用
    Rect outRect = new Rect();
    getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect);
    //new一个instance 并且监听render时间是否完成
    mInstance = new WXSDKInstance(this);
    mInstance.registerRenderListener(this);
  }

//render view创建成功的回调。
//playground中,将对应点的行为解耦出来成为mWxAnalyzerDelegate,来处理打点分析
   @Override
  public void onViewCreated(WXSDKInstance wxsdkInstance, View view) {
    View wrappedView = null;
    if(mWxAnalyzerDelegate != null){
      wrappedView = mWxAnalyzerDelegate.onWeexViewCreated(wxsdkInstance,view);
    }
    if(wrappedView != null){
      view = wrappedView;
    }
    if (mContainer != null) {
      mContainer.removeAllViews();
      mContainer.addView(view);
    }
  }



  @Override
  public void onRefreshSuccess(WXSDKInstance wxsdkInstance, int i, int i1) {

  }
//render成功的回调
  @Override
  @CallSuper
  public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
    if(mWxAnalyzerDelegate  != null){
      mWxAnalyzerDelegate.onWeexRenderSuccess(instance);
    }
  }

//出错的回调。
  @Override
  @CallSuper
  public void onException(WXSDKInstance instance, String errCode, String msg) {
    if(mWxAnalyzerDelegate != null){
      mWxAnalyzerDelegate.onException(instance,errCode,msg);
    }
  }

WXSDKInstance中的构造方法

public WXSDKInstance(Context context) {
    //自动生成一个instanceId
    mInstanceId = WXSDKManager.getInstance().generateInstanceId();
    //初始化这个实例
    init(context);
 }

 public void init(Context context) {
    mContext = context;
    //通过这个helper来调用原生的方法
    mNativeInvokeHelper = new NativeInvokeHelper(mInstanceId);
    //生成对应的性能的log
    mWXPerformance = new WXPerformance();
    mWXPerformance.WXSDKVersion = WXEnvironment.WXSDK_VERSION;
    mWXPerformance.JSLibInitTime = WXEnvironment.sJSLibInitTime;
    //用户信息打点
    mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter();
  }
Render方法

IndexActivityonCreate()中,需要设置局域网的IP地址才能连接到本地开发服务器。如果没有的话,会通过加载本地Assets目录下的Js文件进行渲染。

   if (TextUtils.equals(sCurrentIp, DEFAULT_IP)) {
      //如果没有配置,则默认会相同,走到这个位置来加载这个 landing.weex.js文件
      renderPage(WXFileUtils.loadAsset("landing.weex.js", this), getIndexUrl());
    } else {
      renderPageByURL(getIndexUrl());
    }

    //注册一个广播。如果有地方发送了这个广播,则本地会刷新这个文件
    mReloadReceiver = new BroadcastReceiver() {
      @Override
      public void onReceive(Context context, Intent intent) {
        createWeexInstance();
        if (TextUtils.equals(sCurrentIp, DEFAULT_IP)) {
          renderPage(WXFileUtils.loadAsset("landing.weex.js", getApplicationContext()), getIndexUrl());
        } else {
          renderPageByURL(getIndexUrl());
        }
        mProgressBar.setVisibility(View.VISIBLE);
      }
    };
    //注册一个本地广播。比全局广播更加有效率。只在自己的app内能够使用
    LocalBroadcastManager.getInstance(this).registerReceiver(mReloadReceiver, new IntentFilter(WXSDKEngine.JS_FRAMEWORK_RELOAD));

渲染的代码,最终会来到WXSDKInstancerender 方法中

  /**
   * Render template asynchronously
   * 异步的方式来渲染我们的js模板
   * @param pageName, used for performance log. 页面的名称,用在log中
   * @param template bundle js js的模板
   * @param options  os   iphone/android/ipad 设置options的参数。也是用来打点的
   *                 weexversion    Weex version(like 1.0.0)
   *                 appversion     App version(like 1.0.0)
   *                 devid        Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH)
   *                 sysversion    Device system version(like 5.4.4、7.0.4, should be used with os)
   *                 sysmodel     Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE")
   *                 Time    UNIX timestamp, UTC+08:00
   *                 TTID(Optional)
   *                 MarkertId
   *                 Appname(Optional)  tm,tb,qa
   *                 Bundleurl(Optional)  template url
   * @param jsonInitData Initial data for rendering
   * @param flag     RenderStrategy {@link WXRenderStrategy} 加载的策略有异步的方式APPEND_ASYNC("APPEND_ASYNC")和 仅一次加载 APPEND_ONCE("APPEND_ONCE")两种方式可以选择
   */
  public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) {
    if(WXEnvironment.isApkDebugable() && WXPerformance.DEFAULT.equals(pageName)){
      WXLogUtils.e("WXSDKInstance", "Please set your pageName or your js bundle url !!!!!!!");

      if (getUIContext() != null) {
        new AlertDialog.Builder(getUIContext())
            .setTitle("Error: Missing pageName")
            .setMessage("We highly recommend you to set pageName. Call" +
                "\nWXSDKInstance#render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag)\n" +
                "to fix it.")
            .show();
      }

      return;
    }
     //继续进入下一个方法
    renderInternal(pageName,template,options,jsonInitData,flag);
  }


 private void renderInternal(String pageName,
                              String template,
                              Map<String, Object> options,
                              String jsonInitData,
                              WXRenderStrategy flag){
     //如果已经渲染成功,则停止
    if (mRendered || TextUtils.isEmpty(template)) {
      return;
    }
    //设置performance pageName
    mWXPerformance.pageName = (TextUtils.isEmpty(pageName) ? "defaultBundleUrl":pageName);
    if (TextUtils.isEmpty(mBundleUrl)) {
      mBundleUrl = mWXPerformance.pageName;
    }

    WXLogUtils.d("WXSDKInstance", "Start render page: " + pageName);
    
    //监控数据监控
    if (WXTracing.isAvailable()) {
      WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1);
      traceEvent.traceId = mExecJSTraceId;
      traceEvent.iid = mInstanceId;
      traceEvent.tname = "JSThread";
      traceEvent.ph = "B";
      traceEvent.submit();
      mRenderStartNanos = System.nanoTime();
    }
    //创建一个render出来view的锚点容器。一个持有改instance弱应用的FrameLayout-->mRenderContainer
    ensureRenderArchor();

    Map<String, Object> renderOptions = options;
    if (renderOptions == null) {
      renderOptions = new HashMap<>();
    }
    //如果是动态模式,并且动态的url不为空,则会去加载url
    if (WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && renderOptions.get("dynamicMode") == null) {
      renderOptions.put("dynamicMode", "true");
      renderByUrl(pageName, WXEnvironment.sDynamicUrl, renderOptions, jsonInitData, flag);
      return;
    }
    //数据统计
    mWXPerformance.JSTemplateSize = template.length() / 1024f;

    mRenderStartTime = System.currentTimeMillis();
    mRenderStrategy = flag;

    WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName);
    //这里通过WXSDKManager来创建instance
    WXSDKManager.getInstance().createInstance(this, template, renderOptions, jsonInitData);
    mRendered = true;
  }

WXSDKManagercreateInstance()

void createInstance(WXSDKInstance instance, String code, Map<String, Object> options, String jsonInitData) {
  //注册到renderManager中
  mWXRenderManager.registerInstance(instance);
  //通过WXBridgeManager createInstance向jsf通信
  mBridgeManager.createInstance(instance.getInstanceId(), code, options, jsonInitData);
  //回调
  if (mLifeCycleCallbacks != null) {
    for (InstanceLifeCycleCallbacks callbacks : mLifeCycleCallbacks) {
      callbacks.onInstanceCreated(instance.getInstanceId());
    }
  }
}

下面兵分两路,分别来看看都做了什么事情

WXRenderManager

WXRenderManager是一个render操作的管理类,并且是线程安全的。主要用来管理RenderActionContextImpl

public class WXRenderManager {
//线程安全的map.存放RenderActionContextImpl
  private ConcurrentHashMap<String, RenderActionContextImpl> mRegistries;
    //其实就是一个ui线程的handler
  private WXRenderHandler mWXRenderHandler;

  public WXRenderManager() {
    mRegistries = new ConcurrentHashMap<>();
    mWXRenderHandler = new WXRenderHandler();
  }

  public RenderActionContext getRenderContext(String instanceId) {
    return mRegistries.get(instanceId);
  }

  //上面来注册,就是创建个RenderActionContextImpl实例,放到map当中。
  //这个RenderActionContextImpl就如它的名字一样,是instance内保存Component信息的类。
   //通过这个类,来完成Component的layout
  public void registerInstance(WXSDKInstance instance) {
    mRegistries.put(instance.getInstanceId(), new RenderActionContextImpl(instance));
  }

  //先省略若干方法
}


/**
* 再来看一下RenderActionContextImpl到底是什么
 * 这个类就是用来renderingView的。而且和WXDomStatement很相似
 */
class RenderActionContextImpl implements RenderActionContext {

  private Map<String, WXComponent> mRegistry;
  private WXSDKInstance mWXSDKInstance;
  /**
   * The container for weex root view.
   */

  public RenderActionContextImpl(WXSDKInstance instance) {
    mWXSDKInstance = instance;
    mRegistry = new HashMap<>();
  }

  /**
   * @see com.taobao.weex.dom.WXDomStatement#destroy()
   */
  public void destroy() {
    mWXSDKInstance = null;
    mRegistry.clear();
  }

  public WXSDKInstance getWXSDKInstance() {
    return mWXSDKInstance;
  }

  /**
   * set layout information of View
   * 设置布局的信息。
   * ref 是 改节点的标识
   * WXDomObject 
   */
  void setLayout(String ref, WXDomObject domObject) {
    WXComponent component = mRegistry.get(ref);
    if (component == null) {
      return;
    }
    component.setLayout(domObject);
  }

  /**
   * set extra information of View
   */
  void setExtra(String ref, Object extra) {
    WXComponent component = mRegistry.get(ref);
    if (component == null) {
      return;
    }
    component.updateExtra(extra);
  }

  @Override
  public WXSDKInstance getInstance() {
    return mWXSDKInstance;
  }

  @Override
  public WXComponent getComponent(String ref) {
    return mRegistry.get(ref);
  }

  //注册
  public void registerComponent(String ref, WXComponent comp) {
    mRegistry.put(ref,comp);
  }

  //清除
  public WXComponent unregisterComponent(String ref) {
    return mRegistry.remove(ref);
  }
}

WXBridgeManager
 /**
   * Create instance.
   */
  public void createInstance(final String instanceId, final String template,
                             final Map<String, Object> options, final String data) {
    final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
    if (instance == null) {
      WXLogUtils.e("WXBridgeManager", "createInstance failed, SDKInstance is not exist");
      return;
    }
     //如果任一个为空,则直接报错
    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(template) || mJSHandler == null) {
      instance.onRenderError(
              WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorCode(),
              WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorMsg() +
      " instanceId==" + instanceId + " template ==" + template + " mJSHandler== " + mJSHandler.toString()
      );
      return;
    }

      //报错检查
    if (!isJSFrameworkInit() && reInitCount == 1 && !WXEnvironment.sDebugServerConnectable) {
      instance.onRenderError(
              WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorCode(),
              WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorMsg() +
      " isJSFrameworkInit==" + isJSFrameworkInit() + " reInitCount == 1" );
      post(new Runnable() {
        @Override
        public void run() {
          initFramework("");
        }
      }, instanceId);
      return;
    }

    //创建一个ModuleManager。由上一章知道,moduleManager是缓存和管理module的类
    WXModuleManager.createDomModule(instance);
    //通过JSThread发送
    post(new Runnable() {
      @Override
      public void run() {
        long start = System.currentTimeMillis();
        //执行在JSThread中真实的方法
        invokeCreateInstance(instance, template, options, data);
        final long totalTime = System.currentTimeMillis() - start;
        //回调到ui线程的创建结束的方法
        WXSDKManager.getInstance().postOnUiThread(new Runnable() {

            @Override
            public void run() {
               //这里的回调,在playground app中,只是为了打点
            instance.createInstanceFinished(totalTime);
          }
        }, 0);
      }
    }, instanceId);
  }


  private void invokeCreateInstance(@NonNull WXSDKInstance instance, String template,
                                    Map<String, Object> options, String data) {
    //如果未初始化jsf,则报错
    initFramework("");

    if (mMock) {
      mock(instance.getInstanceId());
    } else {
      if (!isJSFrameworkInit()) {
        String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized.";
        instance.onRenderError(
                WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorCode(),
                WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorMsg()
        );
        WXLogUtils.e(err);
        return;
      }
      try {
        if (WXEnvironment.isOpenDebugLog()) {
          WXLogUtils.d("createInstance >>>> instanceId:" + instance.getInstanceId()
              + ", options:"
              + WXJsonUtils.fromObjectToJSONString(options)
              + ", data:" + data);
        }
        //创建通信的WXJSObject对象数组进行同时
        WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
            instance.getInstanceId());
        WXJSObject instanceObj = new WXJSObject(WXJSObject.String,
            template);
        WXJSObject optionsObj = new WXJSObject(WXJSObject.JSON,
            options == null ? "{}"
                : WXJsonUtils.fromObjectToJSONString(options));
        WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
            data == null ? "{}" : data);
        WXJSObject[] args = {instanceIdObj, instanceObj, optionsObj,
            dataObj};
        instance.setTemplate(template);
        //将上面的命令,转成了Js的function,调用执行JS的命令,进行创建!
        invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
      } catch (Throwable e) {
        String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause()
                + instance.getTemplateInfo();

        instance.onRenderError(
                WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorCode(),
                WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorMsg() + err);
        WXLogUtils.e(err);
      }
    }
  }

//这个方法其实就是为了输出一个log.然后同执行execJs
 public void invokeExecJS(String instanceId, String namespace, String function,
                           WXJSObject[] args, boolean logTaskDetail) {
     if (WXEnvironment.isOpenDebugLog()) {
      mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
          .append("function:").append(function);
      if (logTaskDetail) {
        mLodBuilder.append(" tasks:").append(argsToJSON(args));
      }
      WXLogUtils.d(mLodBuilder.substring(0));
      mLodBuilder.setLength(0);
    }
    //Execute JavaScript function
    mWXBridge.execJS(instanceId, namespace, function, args);
  }

这里可以看到,最后是用我们的参数,调用了mWXBridge.execJS(instanceId, namespace, function, args);native方法传递给JSF

callNative(...)

execJsnative方法,会反射调用callNative(...)方法。通过这样的方式来回调native方法。

  /**
   * JavaScript uses this methods to call Android code
   *
   * @param instanceId
   * @param tasks
   * @param callback
   */

  public int callNative(String instanceId, byte [] tasks, String callback) {
    try {
     return callNative(instanceId,(JSONArray)WXJsonUtils.parseWson(tasks),callback);
    } catch (Throwable e) {
      //catch everything during call native.
      // if(WXEnvironment.isApkDebugable()){
      WXLogUtils.e(TAG,"callNative throw exception:"+e.getMessage());
      // }
      return 0;
    }
  }

 public int callNative(String instanceId, JSONArray tasks, String callback) {
    long start = System.currentTimeMillis();
    WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
    if(instance != null) {
      instance.firstScreenCreateInstanceTime(start);
    }
    int errorCode = IWXBridge.INSTANCE_RENDERING;
    try {
       //再到WXBridgeManager中进行调用
      errorCode = WXBridgeManager.getInstance().callNative(instanceId, tasks, callback);
    }catch (Throwable e){
      //catch everything during call native.
      // if(WXEnvironment.isApkDebugable()){
        WXLogUtils.e(TAG,"callNative throw exception:"+e.getMessage());
      // }
    }

    if(instance != null) {
      instance.callNativeTime(System.currentTimeMillis() - start);
    }
    if(WXEnvironment.isApkDebugable()){
      if(errorCode == IWXBridge.DESTROY_INSTANCE){
        WXLogUtils.w("destroyInstance :"+instanceId+" JSF must stop callNative");
      }
    }
    return errorCode;
  }

接下来会进行一些native的布局操作,在这编文章内就暂时不深究了。

总结

最后,先看一下注册过程的类结构图


注册过程中的类图.jpg

虽然看了很多源码,但是形成的印象还是很笼统。
上面这个例子中,JSFramework的工作原理基本就展现出来了。大体流程如下图:

接下来详细总结一下JSFramework在整个Native端是如何工作的。

  1. Weex本身是由JSFramework和Native Render、和虚拟的Dom,这三大部分组成。本文覆盖的范围还主要在jsf的初始化和native render调用的开始。
  2. 首先,JSFramework是全局单例,但是WXSDKInstance是每个页面自己的实例。
  3. Weex内,我们看到的线程就存在了JSThread、UiThread的两种线程相互工作
  4. 渲染的核心最根本的在于native通过execJs的native方法,调用js的function进行工作。然后再通过callNative的方法进行回调native对应的代码

更多

本篇文章只大概讲述了Weex是如何在Android Native端跑起来的原理,但是关于Weex其实还有很多很多疑问没有弄清。
Weex内的线程模型,线程内相互是如何通信的?

比如说在Vue.js页面更改了一个页面元素,是怎么能让Native页面及时的变更?

Weex的页面是怎么通过FlexBox算法进行渲染的?

前端页面是如何打包成JS bundle的?

.we和.vue文件是怎么通过DSL被翻译的?

如何利用JS的Runtime写一些强大的JSService?

webpackBootstrap和weex-loader是如何生成最终的JS代码的,中间有哪些优化?……

推荐阅读更多精彩内容