背景:

由于公司的RN库版本是0.4.x,调研后决定升级到0.6.x。之前没有接触过RN,在上手之前,现在网上大约进行一下基础知识的学习,并将总结性的结论一致放在这里,便利以后查阅。

参阅:

ReactNative iOS 框架源码解析

【React Native】从源码一步一步解析它的完结原理

ReactNative源码解析——通讯机制详解(1/2)

ReactNative源码解析——通讯机制详解(2/2)

ReactNative源码解析——烘托机制详解

全体架构、流程

  1. 首先写好JSX代码(React框架便是运用JSX语法)
  2. 把JSX代码解析成javaScript代码
  3. OC读取JS文件
  4. 把javaScript代码读取出来,利用JavaScriptCore履行
  5. javaScript代码返回一个数组,数组中会描述OC目标,OC目标的特点,OC目标所需求履行的办法,这样就能让这个目标设置特点,而且调用办法。

  • 如果你了解这些东西的实质其实就很清楚了。动态或许脚本言语要跟本地言语互通要具备如下几点:
    1. 本地言语有一个runtime机制来对目标的办法调用进行动态解析。
    2. 本地言语一定有一个脚本的解析引擎
    3. 树立一个脚本言语到本地言语的映射表,KEY是脚本言语知道的符号,VALUE是本地言语知道的符号。经过这个映射表来构建从脚本到本地的调用。
  • 经过上述3个准则,无论是RN, JSPATCH, WEEKS, WEX都是运用同样的机制。。没有什么神秘可言,也没有什么复杂度可言了。。。

发动流程

React Native发动流程(iOS)

React Native加载JS源码流程(iOS)

烘托原理

通讯机制

ReactNative 的初始化

native module 注册

  • 要将 Native module(类、接口)曝露给 JS,module需求完结RCTBridgeModule协议,而且在完结中要刺进RCT_EXPORT_MODULE宏。具体曝露的办法也需求经过RCT_EXPORT_METHOD宏定义。
  • RCT_EXPORT_MODULE的源码:

    RCT_EXTERN void RCTRegisterModule(Class);
      +(NSString *)moduleName                   
      {                                         
        return @ #js_name;                      
      }                                         
      +(void)load                               
      {                                         
        RCTRegisterModule(self);                
      }
    
  • 经过上图流程,native module注册最终定位RCTCxxBridge._initModulesWithDispatchGroup
    - (void)_initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup
    {
        NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new];
        NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];
        NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];
        // Set up moduleData for automatically-exported modules
        for (Class moduleClass in RCTGetModuleClasses()) {
            NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
            moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
            moduleDataByName[moduleName] = moduleData;
            [moduleClassesByID addObject:moduleClass];
            [moduleDataByID addObject:moduleData];       
        }
        // Store modules
        _moduleDataByID = [moduleDataByID copy];
        _moduleDataByName = [moduleDataByName copy];
        _moduleClassesByID = [moduleClassesByID copy];
    }
    
  • 上述代码第8RCTGetModuleClasses()即是获取经过RCTRegisterModule注册的 module 类(即一切曝露给 JS 的类)
  • 至此,一切需求曝露给 JS 的 module 都已注册完结,并以RCTModuleData格式存储在RCTCxxBridge中。
  • 大部分 module 都是懒加载,只有那些需求在主线程完结初始化以及有常量需求导出的 module才会在注册时实例化。

JS 获取 native module 信息

  • 收集了一切曝露给 JS 的 module(也可称之为生成了一份 native module 注册表);
  • 在 JS Context 中设置了nativeModuleProxy以及nativeFlushQueueImmediate
  • 初始化了相关的类,如:NativeToJsBridgeJsToNativeBridge以及JSCExecutor

JS 调用 native module

  • NativeModules.moduleName — 该过程主要是获取 native module 的信息(moduleID、methodID),最终封装为 JS object ({methodName: fn});
  • NativeModules.moduleName.methodName(params) — 履行调用。

总结

  • RN 项目中涉及多种言语,但 Native 与 JS 的通讯发生在C++JavaScript间;
  • 双方具体担任通讯的分别是:Native 的JSCExecutor与 JS 的MessageQueue
  • 在 Native 侧保护了一份曝露给 JS 的 module 注册表,在 JS 侧保护了一份曝露给 Native 的 module 注册表;
  • RN 中 Native to JS 的通讯没有运用JavaScriptCore提供的机制(blockJSExport),而是自己完结了一套跨渠道通讯机制。