美文网首页
React Native 探析

React Native 探析

作者: 浮萍向北 | 来源:发表于2018-12-31 18:16 被阅读0次

    ReactNative 介绍

    我们把这个单词拆解成2部分

    • React

    熟悉前端的朋友们可能都知道React.JS这个前端框架,没错整个RN框架的JS代码部分,就是React.JS,所有这个框架的特点,完完全全都可以在RN里面使用(这里还融入了Flux,很好的把传统的MVC重组为dispatch,store和components,Flux架构)

    • Native

    顾名思义,纯源生的native体验,纯源生的UI组件,纯原生的触摸响应,纯源生的模块功能

    当React.JS已经计算完每个页面元素的位置大小,本来要传给浏览器,让浏览器进行渲染,这时候我们不传给浏览器了,而是通过一个JS/OC的桥梁,去通过[[UIView alloc]initWithFrame:frame]的OC代码,把这个界面元素渲染了,那我们就相当于用React.JS绘制出了一个native的View

    拿我们刚刚绘制出得native的View,当他发生native源生的- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event触摸事件的时候,通过一个OC/JS的桥梁,去调用React.JS里面写好的点击事件JS代码

    这样React.JS还是那个React.JS,他的使用方法没发生变化,但是却获得了纯源生native的体验,native的组件渲染,native的触摸响应

    于是,这个东西就叫做React-Native。

    React Native通信机制

    模块配置表

    首先OC要告诉JS它有什么模块,模块里有什么方法,JS才知道有这些方法后才有可能去调用这些方法。这里的实现是OC生成一份模块配置表传给JS,配置表里包括了所有模块和模块里方法的信息。例:

    {
        "remoteModuleConfig": {
            "RCTSQLManager": {
                "methods": {
                    "query": {
                        "type": "remote",
                        "methodID": 0
                    }
                },
                "moduleID": 4
            },
            ...
         },
    }
    

    OC端和JS端分别各有一个bridge,两个bridge都保存了同样一份模块配置表,JS调用OC模块方法时,通过bridge里的配置表把模块方法转为模块ID和方法ID传给OC,OC通过bridge的模块配置表找到对应的方法执行.

    模块配置表生成

    OC的模块配置表式怎么来?我们在新建一个OC模块时,JS和OC都不需要为新的模块手动去某个地方添加一些配置,模块配置表是自动生成的,只要项目里有一个模块,就会把这个模块加到配置表上,那这个模块配置表是怎样自动生成的呢?分两个步骤:

    • 取所有模块类
      每个模块类都实现了RCTBridgeModule接口,可以通过runtime接口objc_getClassList或objc_copyClassList取出项目里所有类,然后逐个判断是否实现了RCTBridgeModule接口,就可以找到所有模块类

    • 取模块里暴露给JS的方法
      一个模块里可以有很多方法,一些是可以暴露给JS直接调用的,一些是私有的不想暴露给JS,怎样做到提取这些暴露的方法呢?我能想到的方法是对要暴露的方法名制定一些规则,比如用RCTExport_作为前缀,然后用runtime方法class_getInstanceMethod取出所有方法名字,提取以RCTExport_为前缀的方法,但这样做恶心的地方是每个方法必须加前缀。React Native用了另一种黑魔法似的方法解决这个问题:编译属性attribute

    调用流程

    通过上面的图片 我们大概了解之间怎么去交互的下面我们们一步一步分析它们都做了什么?

    1.JS端调用某个OC模块暴露出来的方法。

    2.把上一步的调用分解为ModuleNameMethodNamearguments,在交给MessageQueue处理。

    在初始化时模块配置表上的每一个模块都生成了对应的remoteModule对象,对象里也生成了跟模块配置表里一一对应的方法,这样方法里可以拿到自身的模块名,方法名,并对CallBack进行处理,在移交给MessageQueue。

    3.在这一步把JScallback函数缓存在MessageQueue的一个成员变量里,用CallbackID代表callback。在通过保存在MessageQueue的模块配置表把上一步传进来的ModuleNameMethodName转为ModuleIDMethodID

    4.把上述步骤得到的ModuleID,MethodId,CallbackID和其他参数argus传给OC

    JS不会主动传递数据给OC,在调OC方法时,会把ModuleID,MethodID等数据加到一个队列里,等OC过来调JS的任意方法时,再把这个队列返回给OC,此时OC再执行这个队列里要调用的方法。

    5.OC接收到消息,通过模块配置表拿到对应的模块和方法。

    实际上模块配置表已经经过处理了,跟JS一样,在初始化时OC也对模块配置表上的每一个模块生成了对应的实例并缓存起来,模块上的每一个方法也都生成了对应的RCTModuleMethod对象,这里通过ModuleID和MethodID取到对应的Module实例和RCTModuleMethod实例进行调用。具体实现在_handleRequestNumber:moduleID:methodID:params:。

    6.RCTModuleMethodJS传过来的每一个参数进行处理。

    RCTModuleMethod可以拿到OC要调用的目标方法的每个参数类型,处理JS类型到目标类型的转换,所有JS传过来的数字都是NSNumber,这里会转成对应的int/long/double等类型,更重要的是会为block类型参数的生成一个block。

    例如-(void)select:(int)index response:(RCTResponseSenderBlock)callback 这个方法,拿到两个参数的类型为int,block,JS传过来的两个参数类型是NSNumber,NSString(CallbackID),这时会把NSNumber转为int,NSString(CallbackID)转为一个block,block的内容是把回调的值和CallbackID传回给JS。

    这些参数组装完毕后,通过NSInvocation动态调用相应的OC模块方法

    7.OC模块方法调用完,执行block回调。

    8.调用到第6步说明的RCTModuleMethod生成的block

    9.block里带着CallbackIDblock传过来的参数去调JSMessageQueue的方法invokeCallbackAndReturnFlushedQueue

    10.MessageQueue通过CallbackID找到相应的JS callback方法。

    11.调用callback方法,并把OC带过来的参数一起传过去,完成回调。

    整个流程就是这样,简单概括下:JS函数调用转ModuleID/MethodID -> callback转CallbackID -> OC根据ID拿到方法 -> 处理参数 -> 调用OC方法 -> 回调CallbackID -> JS通过CallbackID拿到callback执行。

    相关文章

      网友评论

          本文标题:React Native 探析

          本文链接:https://www.haomeiwen.com/subject/mbjwlqtx.html