一、weexSDK初始化流程
WXSDKEngine.initialize(Application application,InitConfig config);//WXSDKEngine的init方法已经被弃用,weex的初始化需要使用下面这个initialize方法public static void initialize(Application application,InitConfig config){synchronized (mLock) {//如果已经初始化过那么直接returnif (mIsInit) {return;}long start = System.currentTimeMillis();WXEnvironment.sSDKInitStart = start;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);WXEnvironment.sSDKInitInvokeTime = System.currentTimeMillis()-start;WXLogUtils.renderPerformanceLog("SDKInitInvokeTime", WXEnvironment.sSDKInitInvokeTime);//监测weex表现的的一个检测器的初始化WXPerformance.init();mIsInit = true;}}
此方法最终会调用doInitInternal(application,config),其余部分的代码叔要是设置apk的debug和log模式,计算weexSDK初始化所需时间等。那么接下来看doInitInternal(application,config)的代码。
private static void doInitInternal(final Application application,final InitConfig config){//这里给WXEnvironment中的application赋值,方便后续使用WXEnvironment.sApplication = application;if(application == null){//application为空的话报错WXLogUtils.e(TAG, " doInitInternal application is null");WXExceptionUtils.commitCriticalExceptionRT(null,WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,"doInitInternal",WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "WXEnvironment sApplication is null",null);}//weex环境初始化标识设置为falseWXEnvironment.JsFrameworkInit = false;//通过单例模式获取一个WXBridgeManager的唯一实例,使用WXBridgeManager开启一个安全的线程初始化weex框架。//开启安全线程的细节暂时不深究,这里主要看weex框架的初始化流程WXBridgeManager.getInstance().post(new Runnable() {@Overridepublic void run() {//开始初始化时间long start = System.currentTimeMillis();//获取WXSDKManager实例WXSDKManager sm = WXSDKManager.getInstance();//使用sm监听weex框架初始化,我们可以通过WXSDKManager.registerStatisticsListener()//注册一个监听器sm.onSDKEngineInitialize();//设置weex框架配置项if(config != null ) {sm.setInitConfig(config);}//初始化so文件加载器,后两个参数分别为初始化时的加载器和监听器。WXSoInstallMgrSdk.init(application,sm.getIWXSoLoaderAdapter(),sm.getWXStatisticsListener());//加载so库文件,如不设置自定义的IWXSoLoaderAdapter,那么采用系统默认方式加载boolean isSoInitSuccess = WXSoInstallMgrSdk.initSo(V8_SO_NAME, 1, config!=null?config.getUtAdapter():null);if (!isSoInitSuccess) {//加载失败报错WXExceptionUtils.commitCriticalExceptionRT(null,WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,"doInitInternal",WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "isSoInit false",null);return;}//使用WXSDKManager初始化jsFramwork,就是讲weexSdk中assets下的js文件拷贝到缓存目录中,使用so的native方法执行sm.initScriptsFramework(config!=null?config.getFramework():null);//计算初始化所用时间WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);}});//注册weexSDK内置的一系列Component和Moduleregister();}
二、组件(Component)注册流程
按照weex官网的流程,首先我们会调用WXSDKEngine的registerComponent(String type, Class<? extends WXComponent> clazz)方法。
我们在WXSDKEngine源码中找到这个方法:
public static boolean registerComponent(String type, Class<? extends WXComponent> clazz) throws WXException {return WXComponentRegistry.registerComponent(type, new SimpleComponentHolder(clazz),new HashMap<String, Object>());}
我们发现该方法实际上是调用了WXComponentRegistry.registerComponent(xx,xx,xx)方法,我们先对SimpleComponentHolder留意,后续会用到。那么我们跟踪到WXComponentRegistry中查看registerComponent方法的实现。
public static synchronized boolean registerComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) throws WXException {if (holder == null || TextUtils.isEmpty(type)) {return false;}//execute task in js thread to make sure register order is same as the order invoke register method.//在js线程执行这个注册组件的任务,以确保我们注册组件的顺序与调用注册方法的顺序一致。WXBridgeManager.getInstance().post(new Runnable() {@Overridepublic void run() {try {Map<String, Object> registerInfo = componentInfo;if (registerInfo == null){registerInfo = new HashMap<>();}//设置注册信息registerInfo.put("type",type);//holder是之前让大家留意的SimpleComponentHolder类registerInfo.put("methods",holder.getMethods());//生成原生组件映射registerNativeComponent(type, holder);//将组件注册信息传递到jsFramwork,生成js中解析vue中原生component是所需的Json映射registerJSComponent(registerInfo);//sComponentInfos是js解析需要使用的类,包含所有组件的注册信息sComponentInfos.add(registerInfo);} catch (WXException e) {WXLogUtils.e("register component error:", e);}}});return true;}
1、holder.getMethods();
此处的holder对象即之前让大家留意的new SimpleComponentHolder(clazz),我们跟踪源码看一下这个方法的实现
public static Pair<Map<String,Invoker>,Map<String,Invoker>> getMethods(Class clz){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;}if (anno instanceof WXComponentProp) {String name = ((WXComponentProp) anno).name();methods.put(name, new MethodInvoker(method,true));break;}else if(anno instanceof JSMethod){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);}
代码很简单,我们可以看出这个方法获取了要注册的Component的所有属性和方法,并把它们方法两个map集合中,最后将两个map封装成Pair返回。
时间上就是通过对WXComponent.Class对象的解析获取了其所有的属性和方法(通过WXComponentProp和JSMethod注解)。
获取成功后通过registerInfo.put("methods",holder.getMethods());将这些属性和方法信息放到组件的注册信息中。
2、registerNativeComponent(type, holder);
此方法属于用于生成原生组件的映射,用于对js文件的解析,我们同样来看一下此方法的实现。
//WXComponentRegistry.javaprivate static boolean registerNativeComponent(String type, IFComponentHolder holder) throws WXException {try {holder.loadIfNonLazy();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;}
holder.loadIfNonLazy();这行代码调用了SimpleComponentHolder的loadIfNonLazy方法对holder进行了加载,实际上是将组件属性和方法信息保存在SimpleComponentHolder类型的对象holder中,之后将holder保存到sTypeComponentMap中,这是一个component组件的映射集合Map,它是一个静态变量。后续与sComponentInfos配合实现对js文件中component组件的解析(将编译成的Json对象映射解析成原生组件)。loadIfNonLazy()方法实现如下,比较简单,不在详细说明,看注释即可。
//SimpleComponentHolder.java@Overridepublic void loadIfNonLazy() {//获取类中所有注解Annotation[] annotations = mClz.getDeclaredAnnotations();for (Annotation annotation :annotations) {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());}//通过getMethods()方法获取属性和方法信息Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = getMethods(mClz);//保存属性和方法信息到自身mPropertyInvokers = methodPair.first;mMethodInvokers = methodPair.second;}
3、registerJSComponent(registerInfo);
此方法用于将组件的属性和方法信息转换成对象的Json对象。
//WXComponentRegistry.javaprivate static boolean registerJSComponent(Map<String, Object> componentInfo) throws WXException {ArrayList<Map<String, Object>> coms = new ArrayList<>();coms.add(componentInfo);WXSDKManager.getInstance().registerComponents(coms);return true;}//WXSDKManager.javapublic void registerComponents(List<Map<String, Object>> components) {mBridgeManager.registerComponents(components);}最终调用的是WXBridgeManager的invokeRegisterComponents方法。实现如下,我们结合注释说明一下实现过程。//WXBridgeManager.java/*** Registered component*/public void registerComponents(final List<Map<String, Object>> components) {//js线程处理器或者组件的集合为空则之间返回if (mJSHandler == null || components == null|| components.size() == 0) {return;}//在JsThred中进行组件注册post(new Runnable() {@Overridepublic void run() {invokeRegisterComponents(components, mRegisterComponentFailList);}}, null);}//注册组件private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {//failReceiver是一个注册失败的组件的集合if (components == failReceiver) {throw new RuntimeException("Fail receiver should not use source.");}//jsFramwork初始化未完成就将组件放入到注册失败的集合中if (!isJSFrameworkInit()) {WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");for (Map<String, Object> comp : components) {failReceiver.add(comp);}return;}if (components == null) {return;}//将通过组件的映射信息将其转化为JsonWXJSObject[] args = {new WXJSObject(WXJSObject.JSON,WXJsonUtils.fromObjectToJSONString(components))};try {//通过调用WXBridge的native方法execJS(),调用main.js中的registerComponent方法注册组件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,METHOD_REGISTER_COMPONENTS,WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorMsg()+ args.toString()+ WXLogUtils.getStackTrace(e),null);}}
三、模块(Module)注册流程
下面是相关实现代码,只写一下简单的注释,模块注册流程与组件注册很类似,不再详细说明,感兴趣可以尝试自己阅读源码分析一下。
//WXSDKEnginepublic static boolean registerModule(String moduleName, Class<? extends WXModule> moduleClass) throws WXException {return registerModule(moduleName, moduleClass,false);}public static <T extends WXModule> boolean registerModule(String moduleName, Class<T> moduleClass,boolean global) throws WXException {return moduleClass != null && registerModule(moduleName, new TypeModuleFactory<>(moduleClass), global);}public static <T extends WXModule> boolean registerModule(String moduleName, ModuleFactory factory, boolean global) throws WXException {//在WXSDKEngine中最终调用WXModuleManager.registerModule(moduleName, factory,global)return WXModuleManager.registerModule(moduleName, factory,global);}//WXModuleManager/*** Register module to JavaScript and Android*/public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException {if (moduleName == null || factory == null) {return false;}if (TextUtils.equals(moduleName, WXDomModule.WXDOM)) {WXLogUtils.e("Cannot registered module with name 'dom'.");return false;}try {//这句代码不知道为啥写,因为后面执行了相同的代码,就是将持有Module类信息//的TypeModuleFactory对象保存到sModuleFactoryMap中//去。不知道是不是源码写错了,有高见的同学请赐教sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));} catch (Throwable e) {}//execute task in js thread to make sure register order is same as the order invoke register method.WXBridgeManager.getInstance().post(new Runnable() {@Overridepublic void run() {if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);}try {//原生代码中注册module模块的类信息registerNativeModule(moduleName, factory);} catch (WXException e) {WXLogUtils.e("registerNativeModule" + e);}if (global) {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);}}registerJSModule(moduleName, factory);}});return true;}//原生代码中注册module模块的类信息static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException {if (factory == null) {return false;}try {if (!sModuleFactoryMap.containsKey(moduleName) ) {//将持有Module类信息的TypeModuleFactory对象保存到sModuleFactoryMap中去sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(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[]WXLogUtils.e("[WXModuleManager] registerNativeModule Error moduleName:" + moduleName + " Error:" + e.toString());}return true;}//在Js中注册module模块的方法和名称信息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的invokeRegisterModules方法//WXBridgeManagerprivate 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;}//将modules转换成WXJSObjectWXJSObject[] args = {new WXJSObject(WXJSObject.JSON,WXJsonUtils.fromObjectToJSONString(modules))};try {//调用WXBrige的native方法在js中注册modulemWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args);try {Iterator<String> iter = modules.keySet().iterator();while (iter.hasNext()) {String module = iter.next();if (module != null) {WXModuleManager.resetModuleState(module, true);WXLogUtils.e("[WXBridgeManager]invokeRegisterModules METHOD_REGISTER_MODULES success module:" + module);}}} catch (Throwable e) {}} catch (Throwable e) {WXExceptionUtils.commitCriticalExceptionRT(null,WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES,"invokeRegisterModules", WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +" \n " + e.getMessage() + modules.entrySet().toString(),null );WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", e);}}
总结:
通过对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源码的阅读来具体分析界面渲染的原理。**
