一、weexSDK初始化流程

  1. WXSDKEngine.initialize(Application application,InitConfig config);
  2. //WXSDKEngine的init方法已经被弃用,weex的初始化需要使用下面这个initialize方法
  3. public static void initialize(Application application,InitConfig config){
  4. synchronized (mLock) {
  5. //如果已经初始化过那么直接return
  6. if (mIsInit) {
  7. return;
  8. }
  9. long start = System.currentTimeMillis();
  10. WXEnvironment.sSDKInitStart = start;
  11. if(WXEnvironment.isApkDebugable()){
  12. WXEnvironment.sLogLevel = LogLevel.DEBUG;
  13. }else{
  14. if(WXEnvironment.sApplication != null){
  15. WXEnvironment.sLogLevel = LogLevel.WARN;
  16. }else {
  17. WXLogUtils.e(TAG,"WXEnvironment.sApplication is " + WXEnvironment.sApplication);
  18. }
  19. }
  20. doInitInternal(application,config);
  21. WXEnvironment.sSDKInitInvokeTime = System.currentTimeMillis()-start;
  22. WXLogUtils.renderPerformanceLog("SDKInitInvokeTime", WXEnvironment.sSDKInitInvokeTime);
  23. //监测weex表现的的一个检测器的初始化
  24. WXPerformance.init();
  25. mIsInit = true;
  26. }
  27. }

此方法最终会调用doInitInternal(application,config),其余部分的代码叔要是设置apk的debug和log模式,计算weexSDK初始化所需时间等。那么接下来看doInitInternal(application,config)的代码。

  1. private static void doInitInternal(final Application application,final InitConfig config){
  2. //这里给WXEnvironment中的application赋值,方便后续使用
  3. WXEnvironment.sApplication = application;
  4. if(application == null){//application为空的话报错
  5. WXLogUtils.e(TAG, " doInitInternal application is null");
  6. WXExceptionUtils.commitCriticalExceptionRT(null,
  7. WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
  8. "doInitInternal",
  9. WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "WXEnvironment sApplication is null",
  10. null);
  11. }
  12. //weex环境初始化标识设置为false
  13. WXEnvironment.JsFrameworkInit = false;
  14. //通过单例模式获取一个WXBridgeManager的唯一实例,使用WXBridgeManager开启一个安全的线程初始化weex框架。
  15. //开启安全线程的细节暂时不深究,这里主要看weex框架的初始化流程
  16. WXBridgeManager.getInstance().post(new Runnable() {
  17. @Override
  18. public void run() {
  19. //开始初始化时间
  20. long start = System.currentTimeMillis();
  21. //获取WXSDKManager实例
  22. WXSDKManager sm = WXSDKManager.getInstance();
  23. //使用sm监听weex框架初始化,我们可以通过WXSDKManager.registerStatisticsListener()
  24. //注册一个监听器
  25. sm.onSDKEngineInitialize();
  26. //设置weex框架配置项
  27. if(config != null ) {
  28. sm.setInitConfig(config);
  29. }
  30. //初始化so文件加载器,后两个参数分别为初始化时的加载器和监听器。
  31. WXSoInstallMgrSdk.init(application,
  32. sm.getIWXSoLoaderAdapter(),
  33. sm.getWXStatisticsListener());
  34. //加载so库文件,如不设置自定义的IWXSoLoaderAdapter,那么采用系统默认方式加载
  35. boolean isSoInitSuccess = WXSoInstallMgrSdk.initSo(V8_SO_NAME, 1, config!=null?config.getUtAdapter():null);
  36. if (!isSoInitSuccess) {//加载失败报错
  37. WXExceptionUtils.commitCriticalExceptionRT(null,
  38. WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
  39. "doInitInternal",
  40. WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "isSoInit false",
  41. null);
  42. return;
  43. }
  44. //使用WXSDKManager初始化jsFramwork,就是讲weexSdk中assets下的js文件拷贝到缓存目录中,使用so的native方法执行
  45. sm.initScriptsFramework(config!=null?config.getFramework():null);
  46. //计算初始化所用时间
  47. WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;
  48. WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);
  49. }
  50. });
  51. //注册weexSDK内置的一系列Component和Module
  52. register();
  53. }

二、组件(Component)注册流程

按照weex官网的流程,首先我们会调用WXSDKEngine的registerComponent(String type, Class<? extends WXComponent> clazz)方法。
我们在WXSDKEngine源码中找到这个方法:

  1. public static boolean registerComponent(String type, Class<? extends WXComponent> clazz) throws WXException {
  2. return WXComponentRegistry.registerComponent(type, new SimpleComponentHolder(clazz),new HashMap<String, Object>());
  3. }

我们发现该方法实际上是调用了WXComponentRegistry.registerComponent(xx,xx,xx)方法,我们先对SimpleComponentHolder留意,后续会用到。那么我们跟踪到WXComponentRegistry中查看registerComponent方法的实现。

  1. public static synchronized boolean registerComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) throws WXException {
  2. if (holder == null || TextUtils.isEmpty(type)) {
  3. return false;
  4. }
  5. //execute task in js thread to make sure register order is same as the order invoke register method.
  6. //在js线程执行这个注册组件的任务,以确保我们注册组件的顺序与调用注册方法的顺序一致。
  7. WXBridgeManager.getInstance()
  8. .post(new Runnable() {
  9. @Override
  10. public void run() {
  11. try {
  12. Map<String, Object> registerInfo = componentInfo;
  13. if (registerInfo == null){
  14. registerInfo = new HashMap<>();
  15. }
  16. //设置注册信息
  17. registerInfo.put("type",type);
  18. //holder是之前让大家留意的SimpleComponentHolder类
  19. registerInfo.put("methods",holder.getMethods());
  20. //生成原生组件映射
  21. registerNativeComponent(type, holder);
  22. //将组件注册信息传递到jsFramwork,生成js中解析vue中原生component是所需的Json映射
  23. registerJSComponent(registerInfo);
  24. //sComponentInfos是js解析需要使用的类,包含所有组件的注册信息
  25. sComponentInfos.add(registerInfo);
  26. } catch (WXException e) {
  27. WXLogUtils.e("register component error:", e);
  28. }
  29. }
  30. });
  31. return true;
  32. }

以上有几行代码需要在跟踪代码进一步分析:

1、holder.getMethods();

此处的holder对象即之前让大家留意的new SimpleComponentHolder(clazz),我们跟踪源码看一下这个方法的实现

  1. public static Pair<Map<String,Invoker>,Map<String,Invoker>> getMethods(Class clz){
  2. Map<String, Invoker> methods = new HashMap<>();
  3. Map<String, Invoker> mInvokers = new HashMap<>();
  4. Annotation[] annotations;
  5. Annotation anno;
  6. try {
  7. for (Method method : clz.getMethods()) {
  8. try {
  9. annotations = method.getDeclaredAnnotations();
  10. for (int i = 0, annotationsCount = annotations.length;
  11. i < annotationsCount; ++i) {
  12. anno = annotations[i];
  13. if(anno == null){
  14. continue;
  15. }
  16. if (anno instanceof WXComponentProp) {
  17. String name = ((WXComponentProp) anno).name();
  18. methods.put(name, new MethodInvoker(method,true));
  19. break;
  20. }else if(anno instanceof JSMethod){
  21. JSMethod methodAnno = (JSMethod)anno;
  22. String name = methodAnno.alias();
  23. if(JSMethod.NOT_SET.equals(name)){
  24. name = method.getName();
  25. }
  26. mInvokers.put(name, new MethodInvoker(method,methodAnno.uiThread()));
  27. break;
  28. }
  29. }
  30. } catch (ArrayIndexOutOfBoundsException | IncompatibleClassChangeError e) {
  31. //ignore: getDeclaredAnnotations may throw this
  32. }
  33. }
  34. }catch (IndexOutOfBoundsException e){
  35. e.printStackTrace();
  36. //ignore: getMethods may throw this
  37. }
  38. return new Pair<>(methods,mInvokers);
  39. }

代码很简单,我们可以看出这个方法获取了要注册的Component的所有属性和方法,并把它们方法两个map集合中,最后将两个map封装成Pair返回。
时间上就是通过对WXComponent.Class对象的解析获取了其所有的属性和方法(通过WXComponentPropJSMethod注解)。
获取成功后通过registerInfo.put("methods",holder.getMethods());将这些属性和方法信息放到组件的注册信息中。

2、registerNativeComponent(type, holder);

此方法属于用于生成原生组件的映射,用于对js文件的解析,我们同样来看一下此方法的实现。

  1. //WXComponentRegistry.java
  2. private static boolean registerNativeComponent(String type, IFComponentHolder holder) throws WXException {
  3. try {
  4. holder.loadIfNonLazy();
  5. sTypeComponentMap.put(type, holder);
  6. }catch (ArrayStoreException e){
  7. e.printStackTrace();
  8. //ignore: ArrayStoreException: java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
  9. }
  10. return true;
  11. }

holder.loadIfNonLazy();这行代码调用了SimpleComponentHolderloadIfNonLazy方法对holder进行了加载,实际上是将组件属性和方法信息保存在SimpleComponentHolder类型的对象holder中,之后将holder保存到sTypeComponentMap中,这是一个component组件的映射集合Map,它是一个静态变量。后续与sComponentInfos配合实现对js文件中component组件的解析(将编译成的Json对象映射解析成原生组件)。
loadIfNonLazy()方法实现如下,比较简单,不在详细说明,看注释即可。

  1. //SimpleComponentHolder.java
  2. @Override
  3. public void loadIfNonLazy() {
  4. //获取类中所有注解
  5. Annotation[] annotations = mClz.getDeclaredAnnotations();
  6. for (Annotation annotation :
  7. annotations) {
  8. if (annotation instanceof Component){
  9. if(!((Component) annotation).lazyload() && mMethodInvokers == null){
  10. //通过此方法获得组件类的方法和属性,并保存
  11. generate();
  12. }
  13. return;
  14. }
  15. }
  16. }
  17. private synchronized void generate(){
  18. if(WXEnvironment.isApkDebugable()) {
  19. WXLogUtils.d(TAG, "Generate Component:" + mClz.getSimpleName());
  20. }
  21. //通过getMethods()方法获取属性和方法信息
  22. Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = getMethods(mClz);
  23. //保存属性和方法信息到自身
  24. mPropertyInvokers = methodPair.first;
  25. mMethodInvokers = methodPair.second;
  26. }

3、registerJSComponent(registerInfo);

此方法用于将组件的属性和方法信息转换成对象的Json对象。

  1. //WXComponentRegistry.java
  2. private static boolean registerJSComponent(Map<String, Object> componentInfo) throws WXException {
  3. ArrayList<Map<String, Object>> coms = new ArrayList<>();
  4. coms.add(componentInfo);
  5. WXSDKManager.getInstance().registerComponents(coms);
  6. return true;
  7. }
  8. //WXSDKManager.java
  9. public void registerComponents(List<Map<String, Object>> components) {
  10. mBridgeManager.registerComponents(components);
  11. }
  12. 最终调用的是WXBridgeManagerinvokeRegisterComponents方法。实现如下,我们结合注释说明一下实现过程。
  13. //WXBridgeManager.java
  14. /**
  15. * Registered component
  16. */
  17. public void registerComponents(final List<Map<String, Object>> components) {
  18. //js线程处理器或者组件的集合为空则之间返回
  19. if (mJSHandler == null || components == null
  20. || components.size() == 0) {
  21. return;
  22. }
  23. //在JsThred中进行组件注册
  24. post(new Runnable() {
  25. @Override
  26. public void run() {
  27. invokeRegisterComponents(components, mRegisterComponentFailList);
  28. }
  29. }, null);
  30. }
  31. //注册组件
  32. private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {
  33. //failReceiver是一个注册失败的组件的集合
  34. if (components == failReceiver) {
  35. throw new RuntimeException("Fail receiver should not use source.");
  36. }
  37. //jsFramwork初始化未完成就将组件放入到注册失败的集合中
  38. if (!isJSFrameworkInit()) {
  39. WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");
  40. for (Map<String, Object> comp : components) {
  41. failReceiver.add(comp);
  42. }
  43. return;
  44. }
  45. if (components == null) {
  46. return;
  47. }
  48. //将通过组件的映射信息将其转化为Json
  49. WXJSObject[] args = {new WXJSObject(WXJSObject.JSON,
  50. WXJsonUtils.fromObjectToJSONString(components))};
  51. try {
  52. //通过调用WXBridge的native方法execJS(),调用main.js中的registerComponent方法注册组件
  53. mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args);
  54. } catch (Throwable e) {
  55. WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", e);
  56. WXExceptionUtils.commitCriticalExceptionRT(null,
  57. WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED,
  58. METHOD_REGISTER_COMPONENTS,
  59. WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorMsg()
  60. + args.toString()
  61. + WXLogUtils.getStackTrace(e),
  62. null);
  63. }
  64. }

三、模块(Module)注册流程

下面是相关实现代码,只写一下简单的注释,模块注册流程与组件注册很类似,不再详细说明,感兴趣可以尝试自己阅读源码分析一下。

  1. //WXSDKEngine
  2. public static boolean registerModule(String moduleName, Class<? extends WXModule> moduleClass) throws WXException {
  3. return registerModule(moduleName, moduleClass,false);
  4. }
  5. public static <T extends WXModule> boolean registerModule(String moduleName, Class<T> moduleClass,boolean global) throws WXException {
  6. return moduleClass != null && registerModule(moduleName, new TypeModuleFactory<>(moduleClass), global);
  7. }
  8. public static <T extends WXModule> boolean registerModule(String moduleName, ModuleFactory factory, boolean global) throws WXException {
  9. //在WXSDKEngine中最终调用WXModuleManager.registerModule(moduleName, factory,global)
  10. return WXModuleManager.registerModule(moduleName, factory,global);
  11. }
  12. //WXModuleManager
  13. /**
  14. * Register module to JavaScript and Android
  15. */
  16. public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException {
  17. if (moduleName == null || factory == null) {
  18. return false;
  19. }
  20. if (TextUtils.equals(moduleName, WXDomModule.WXDOM)) {
  21. WXLogUtils.e("Cannot registered module with name 'dom'.");
  22. return false;
  23. }
  24. try {
  25. //这句代码不知道为啥写,因为后面执行了相同的代码,就是将持有Module类信息
  26. //的TypeModuleFactory对象保存到sModuleFactoryMap中
  27. //去。不知道是不是源码写错了,有高见的同学请赐教
  28. sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
  29. } catch (Throwable e) {
  30. }
  31. //execute task in js thread to make sure register order is same as the order invoke register method.
  32. WXBridgeManager.getInstance()
  33. .post(new Runnable() {
  34. @Override
  35. public void run() {
  36. if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {
  37. WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
  38. }
  39. try {
  40. //原生代码中注册module模块的类信息
  41. registerNativeModule(moduleName, factory);
  42. } catch (WXException e) {
  43. WXLogUtils.e("registerNativeModule" + e);
  44. }
  45. if (global) {
  46. try {
  47. WXModule wxModule = factory.buildInstance();
  48. wxModule.setModuleName(moduleName);
  49. sGlobalModuleMap.put(moduleName, wxModule);
  50. } catch (Exception e) {
  51. WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
  52. }
  53. }
  54. registerJSModule(moduleName, factory);
  55. }
  56. });
  57. return true;
  58. }
  59. //原生代码中注册module模块的类信息
  60. static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException {
  61. if (factory == null) {
  62. return false;
  63. }
  64. try {
  65. if (!sModuleFactoryMap.containsKey(moduleName) ) {
  66. //将持有Module类信息的TypeModuleFactory对象保存到sModuleFactoryMap中去
  67. sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
  68. }
  69. }catch (ArrayStoreException e){
  70. e.printStackTrace();
  71. //ignore:
  72. //may throw this exception:
  73. //java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
  74. WXLogUtils.e("[WXModuleManager] registerNativeModule Error moduleName:" + moduleName + " Error:" + e.toString());
  75. }
  76. return true;
  77. }
  78. //在Js中注册module模块的方法和名称信息
  79. static boolean registerJSModule(String moduleName, ModuleFactory factory) {
  80. Map<String, Object> modules = new HashMap<>();
  81. modules.put(moduleName, factory.getMethods());
  82. WXSDKManager.getInstance().registerModules(modules);
  83. return true;
  84. }
  85. 最终会调用WXBridgeManagerinvokeRegisterModules方法
  86. //WXBridgeManager
  87. private void invokeRegisterModules(Map<String, Object> modules, List<Map<String, Object>> failReceiver) {
  88. if (modules == null || !isJSFrameworkInit()) {
  89. if (!isJSFrameworkInit()) {
  90. WXLogUtils.d("[WXinvokeRegisterModulesBridgeManager] invokeRegisterModules: framework.js uninitialized.");
  91. }
  92. failReceiver.add(modules);
  93. return;
  94. }
  95. //将modules转换成WXJSObject
  96. WXJSObject[] args = {new WXJSObject(WXJSObject.JSON,
  97. WXJsonUtils.fromObjectToJSONString(modules))};
  98. try {
  99. //调用WXBrige的native方法在js中注册module
  100. mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args);
  101. try {
  102. Iterator<String> iter = modules.keySet().iterator();
  103. while (iter.hasNext()) {
  104. String module = iter.next();
  105. if (module != null) {
  106. WXModuleManager.resetModuleState(module, true);
  107. WXLogUtils.e("[WXBridgeManager]invokeRegisterModules METHOD_REGISTER_MODULES success module:" + module);
  108. }
  109. }
  110. } catch (Throwable e) {
  111. }
  112. } catch (Throwable e) {
  113. WXExceptionUtils.commitCriticalExceptionRT(null,
  114. WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES,
  115. "invokeRegisterModules", WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +
  116. " \n " + e.getMessage() + modules.entrySet().toString(),
  117. null );
  118. WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", e);
  119. }
  120. }

总结:

通过对component组件注册流程的分析,我们可以推测weex界面中UI组件从vue->js->native界面渲染的大致过程,即vue文件通过weex的weex-loader将vue文件编译成weexSdk可以解析的js文件,其中UI组件实例Json的形式在js中保存的,这个Json就是上面代码中的args,保存了组件的类型、属性、方法等信息。在js文件解析时,我们只需获得这些Json对象,通过type属性获取**WXComponentRegistry的静态变量sTypeComponentMap中对应组件的SimpleComponentHolder对象,竟能将Json对象映射到原生组件的类了。
module的解析过程我们推测与component基本一致。
这个渲染过程只是在对组件和模块注册流程分析后的推测,后续我们会通过对WXSDKInstance源码的阅读来具体分析界面渲染的原理。**