上一篇介绍了Weex中文件夹的作用以及重要性,这一篇将正式开始Weex源码的解析,版本是0.10.0
入口
学习一个开源库,最好是知其思想,找其入口,学其核心。大致思想在第一篇,核心文件夹的分类在第二篇,这一篇就从其入口文件开始学习。
WeexDemo的入口是[WXSDKEngine initSDKEnvironment];
。这个Method的主要代码,如下:
|
|
首先,读取一个叫做main.js的文件内容,然后将其内容作为[WXSDKEngine initSDKEnvironment:script]
初始化的参数。
我们继续来看这个method的代码,如下:
|
|
注册和执行
Register
首先,是对传递进来的js代码做判断,其次调用了一个registerDefaults
的method,代码如下:
|
|
Register Componet
这个method使用了单例模式,对Weex定义的Component、Module、Handler进行注册,注册代码太长,我就不贴了。注册Component,代码如下:
|
|
第一个method中比较让人迷惑的也就是Properties中的参数了,这个其实是vue的渲染模式。@"append":@"tree"
代表是整个vue结点包括子结点生成完之后才会一次性渲染到屏幕,@"append":@"node"
代表是先渲染自身然后再渲染子节点。第二个method中先对name和class进行判空,其次使用WXComponentFactory
进行注册,在这之前先讲几个相关类的功能,免得迷糊。
- WXInvocationConfig:抽象单例类,为什么用单例(懵逼脸),使用时需要子类继承
- WXComponentConfig: 继承
WXInvocationConfig
类,存储每个Component的method、name、classname - WXComponentFactory:单例类,通过字典存储
WXComponentConfig
对象,通过每个WXComponentConfig
对象操作每个Component的method、name、classname。
首先通过WXComponentFactory
调用- (void)registerComponent:(NSString
*)name withClass:(Class)clazz withPros:(NSDictionary *)pros
方法注册。使用Assert判断,然后创建一个WXComponentConfig
对象,先从字典中取,不论是否存在都重新初始化,并将其覆盖,调用[config registerMethods];
将类中的method通过runtime存储在WXComponentConfig
中,存取时加锁保证安全。其次调用- (NSMutableDictionary *)_componentMethodMapsWithName:(NSString *)name
方法获取某个component所有的method,同样是加锁读取。根据有没有properties传递不同参数,如果类中有导出给weex用的方法,那么一定会传递method和name过去。最后调用JS方法registerComponents
,我在vue.js的源码中是找到这个方法了的。对于具体调用JS的过程,会在ExecuteJs模块讲解。
|
|
Register Module
注册Module,代码如下:
|
|
先介绍几个类:
- WXModuleConfig:继承
WXInvocationConfig
类,存储每个Component的method、name - WXModuleFactory:单例类,通过字典操作
WXModuleConfig
对象
查阅下这两个类的代码会发现跟Component结构类似,跟注册Component流程也一样,感觉没必要废话一遍了,最后调用JS方法registerModules
。
Register Handler
注册Handler,代码如下:
|
|
照例介绍几个类:
- WXHandlerFactory:单例类,通过字典存储协议对象,将协议的字符串作为key存储
注册Handler,这个不需要传给weex,因为就是我们Native端进行调用。所以只需要使用WXHandlerFactory操作就行了。
ExecuteJs
最后调用[[WXSDKManager bridgeMgr] executeJsFramework:script];
执行js代码。这一块的知识点是Weex与js的交互,所以需要了解下面几个类,并且对OC中的JavaScriptCore框架有所了解。
首先介绍几个类:
- WXSDKInstance:普通类,这个类是一个类似于Controller的类,具有非常多的功能,目前不需要了解具体功能
- WXSDKManager:单例类,通过一个字典存储所有
WXSDKInstance
实例,key是一个唯一值;一个WXBridgeManager
实例 - WXBridgeManager:单例类,注册,渲染功能都通过调用
WXBridgeContext
对象去跟JS交互 - WXBridgeContext:功能其实不多,render,regist component,regist module,executeJs。就是处理了需要调用js的逻辑。
- WXJSCoreBridge: 这个类才是真正的处理JS调用的类。它实现了WXBridgeProtocol协议,对JavaScriptCore进行了封装,使
WXBridgeContext
调用
现在可以从那句代码开始讲了,[WXSDKManager bridgeMgr]
这个对象是一个单例,他在JS线程调用executeJsFramework
,代码如下:
|
|
先是判空,其次weakSelf防止循环引用,然后在一个叫做"com.taobao.weex.bridge"
的线程调用executeJsFramework
方法,代码如下:
|
|
首先断言当前线程是否是"com.taobao.weex.bridge"
线程,其次断言js代码,使用WXBridgeProtocol
协议对象执行js代码,接着判断js执行是否有异常,有异常输出,无异常,标记读取结束,执行所有的jsService,获取JSFMVersion,执行methodQueue中所有的method,清除信息,结束。
JavaScriptCore
JavaScriptCore简介
上面只是理清了逻辑,如果对JavaScriptCore不了解的人可能看源码时有些懵逼,下面我讲解一些JavaScriptCore的基本概念以及用法。
- JSVirtualMachine:为JavaScript提供运行资源
- JSContext:为JavaScript提供运行环境
- JSValue:可以将JavaScript变量转换为OC变量,也可以将OC变量转换为JavaScript变量
JavaScriptCore示例
这些是Weex使用的JavaScriptCore框架一部分功能,其实还有别的。先来一段代码好了:
简单使用
|
|
首先初始化一个JSContext对象,可以使用JSVirtualMachine
对象初始化,也可以直接初始化,直接初始化系统仍会在内部给你初始化一个JSVirtualMachine
对象,所以这个js运行的资源,不可或缺。
第二句代码的意思是先使用context对象运行js代码,定义一个叫做sum的变量,并赋值2+3,然后将sum赋值给value。
第三句代码输出value的值是5,第四句代码给sum赋值40,第五句输出sum值为40。这主要是因为JSContext是js的环境,而且在js中,所有全局变量和方法都是一个全局变量的属性。所以在第四句,你可以直接从context中取出sum这个变量,并赋值。
异常处理
|
|
另一个要注意的点就是这里,JavaScriptCore会在exceptionHandler
中抛出异常,为了我们能在这个时候做点什么,所以我们赋值给他一个blcok。并且如果你要在block中使用context对象,要么将其作为参数传递进block,要么使用[JSContext currentContext]
获取当前的context。如果直接引用外部的context会造成循环饮用。
invokeMethod
|
|
初始化一个context,将一个名为add的method加入到context中,使用js全局变量调用add方法,并传入参数3,4,输出结果为7。
总结
上面讲了Weex注册的基本逻辑和JavaScriptCore框架的一些基本使用,我想应该对理解Weex框架的运作原理有帮助的。其实剩下的源码还有很多,比如向js端发送消息等,但其实质逃不过上面的流程,所以我认为也没有往下写的必要了。最后,为大家整理下类的调用顺序。