react native 0.50 源码解析 再出发 持续更新

1.核心类

1.1 RCTRootView

一个RCTRootView持有一个RCTBridge成员变量

RCTRootView : UIView
  RCTBridge *bridge;
  UIViewController *reactViewController;
  UIView *contentView;
  UIView *loadingView;

1.2 RCTBridge

一个RCTBridge持有一个RCTCxxBridge成员变量

RCTBridge.h
 @interface RCTBridge : NSObject <RCTInvalidating>

RCTBridge+Private.h
@interface RCTBridge ()
   RCTBridge *batchedBridge;
@end

RCTBridge.m
- (Class)bridgeClass
  return [RCTCxxBridge class];

- (void)setUp
  Class bridgeClass = self.bridgeClass;
  self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
  [self.batchedBridge start];

1.3 RCTCxxBridge

RCTCxxBridge继承自RCTBridge,是RCTBridge的一个变量,拥有弱引用parentBridge指向RCTBridge变量

RCTBridge+Private.h
@interface RCTCxxBridge:RCTBridge

RCTCxxBridge.mm
@interface RCTCxxBridge()
RCTBridge *parentBridge;
@end
//@interface ViewController()后面 ,@end前面的是类扩展,就是创建本类中似有的属性和方法。其他类不能使用的

2.核心流程

2.1 native注册模块表

一个native类需要向js暴露的过程,就是向全局静态数组RCTModuleClasses注册自身class的过程。工程启动后,自动生成全局静态数组RCTModuleClasses,储存注册的class

######RCTBridge
声明全局静态数组:
static NSMutableArray<Class> *RCTModuleClasses;

######native类
需要做到以下两点,
1.实现RCTBridgeModule协议
2.在m文件中放置RCT_EXPORT_MODULE()代码。

RCT_EXPORT_MODULE宏给native类置入load函数。native类在加载过程中,可以自动向RCTModuleClasses注册自身Class。实例如下

ClassA.h
#import <React/RCTBridgeModule.h>
@interface ClassA <RCTBridgeModule>
@end

ClassA.m
RCT_EXPORT_MODULE() ==>
extern __attribute__((visibility("default")))
void RCTRegisterModule(Class);
+ (void)load { RCTRegisterModule(self); }

========================================
宏定义
RCTBridgeModule.h
#define RCT_EXPORT_MODULE(js_name) RCT_EXTERN void RCTRegisterModule(Class); + (NSString *)moduleName { return @#js_name; } + (void)load { RCTRegisterModule(self); }

#define RCT_EXPORT_MODULE(js_name) RCT_EXTERN void RCTRegisterModule(Class);  + (NSString *)moduleName { return @#js_name; }  + (void)load { RCTRegisterModule(self); }

RCTDefindes.h
#define RCT_EXTERN extern __attribute__((visibility("default")))

注册
RCTBridge.m
static NSMutableArray<Class> *RCTModuleClasses;
void RCTRegisterModule(Class moduleClass)
   [RCTModuleClasses addObject:moduleClass];

2.2 RCTCxxBridge初始化模块表

RCTCxxBridge有三个成员变量,_moduleDataByName,_moduleDataByID,_moduleClassesByID

RCTCxxBridge
NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName; //字典,name:RCTModuleData键值对
NSMutableArray<RCTModuleData *> *_moduleDataByID; //RCTModuleData数组
NSMutableArray<Class> *_moduleClassesByID; //Class数组
- (void)start
  [self _initModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];

- (void)_initModules:(NSArray<id<RCTBridgeModule>> *)modules
   withDispatchGroup:(dispatch_group_t)dispatchGroup
    lazilyDiscovered:(BOOL)lazilyDiscovered
  NSArray<RCTModuleData *> *moduleDataById = [self registerModulesForClasses:modules]; //将modules转换成RCTCxxBridge的模块组

- (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses
   for (Class moduleClass in moduleClasses) {
      _moduleDataByName[moduleName] = moduleData;
      [_moduleClassesByID addObject:moduleClass];
      [moduleDataByID addObject:moduleData];
   }
   [_moduleDataByID addObjectsFromArray:moduleDataByID];

2.3 RCTCxxBridge 加载/执行JS资源

 - (void)start
     [self loadSource:^(NSError *error, RCTSource *source)
           {sourceCode = source.data;}]  // 加载JS
     [strongSelf executeSourceCode:sourceCode sync:NO]; //执行JS

- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress
     发送通知RCTBridgeWillDownloadScriptNotification
     RCTSourceLoadBlock onSourceLoad = ^(NSError *error, RCTSource *source)
     {
            发送通知RCTBridgeDidDownloadScriptNotification:RCTSource
     }
    [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:^(NSError *error, RCTSource *source)
     {
          onSourceLoad(error, source);
     }

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
   - (void)executeApplicationScript:(NSData *)script
                             url:(NSURL *)url
                           async:(BOOL)async
  dispatch_block_t completion = ^{
          [self _flushPendingCalls];
          广播通知RCTJavaScriptDidLoadNotification
          [self ensureOnJavaScriptThread:^{
             [self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]];
          }];
     }

- (void)executeApplicationScript:(NSData *)script
                             url:(NSURL *)url
                           async:(BOOL)async
  if (isRAMBundle(script))
      self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
                                            sourceUrlStr.UTF8String, !async);
  else if (self->_reactInstance)
      self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
                                                 sourceUrlStr.UTF8String, !async);

- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
    |=== - (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses
          |---for (Class moduleClass in moduleClasses)
          {
              NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
              moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];

          }

[RCTCxxBridge registerExtraModules]
  • (void)start
    |--- 广播通知---
    RCTJavaScriptWillStartLoadingNotification:@{@"bridge": self}
    |--- 新建并启动js线程 _jsThread
    |--- 注册moduleClass---
    [self registerExtraModules];
    [self _initModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
    |--- 创建工厂并配置---
    std::shared_ptr<JSExecutorFactory> executorFactory;
    |--- 加载js资源---
    [self loadSource:^(NSError error, RCTSource source)
    |--- 执行js---
    [strongSelf executeSourceCode:sourceCode sync:NO];

启动

[AppDelegate didFinishLaunchingWithOptions]
|---获取jsCodeLocation
|---[RCTRootView initWithBundleURL..]
    |---[RCTBridge alloc+init]
        |---设置变量:delegate,bundleURL,moduleProvider, launchOptions
        |---[RCTBridge setUp]
            |---设置变量:bundleURL
            |---[RCTCxxBridge alloc+init]  --> RCTBridge.batchedBridge
            |---[RCTCxxBridge start]

    |---[RCTRootView initWithBridge:...]
          |---注册三个通知,如下
          |---[self bundleFinishedLoading:([_bridge batchedBridge] ?: _bridge)];
                |---RCTRootContentView alloc
                |---[self runApplication:bridge];
                       |---[bridge enqueueJSCall:@"AppRegistry"
                 method:@"runApplication"
                   args:@[moduleName, appParameters]
             completion:NULL];
                |---insertSubview:_contentView

RCTRootView 继承自UIView,内含RCTBridge变量,初始化参数BundleURL/moduleName/Properties/launchOptions。初始化的时候,初始化RCTBridge变量,自我初始化。自我初始化过程:注册三个通知,RCTJavaScriptWillStartLoadingNotification/RCTJavaScriptDidLoadNotification/RCTContentDidAppearNotification

RCTBridge native call js

[RCTBridge enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray *)args completion:(dispatch_block_t)completion]
|---[self.batchedBridge enqueueJSCall:module method:method args:args completion:completion];

RCTCxxBridge 成员:
_moduleClassesByID
_moduleDataByID
_moduleDataByName 可变字典:string(moduleName):RCTModuleData(Data)的键值队
RCTCxxBridge native call js,可以从任意线程中调起

RCTBridge
- (void)setUp
   URL转换
   self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
   [self.batchedBridge start];

- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
   [self.batchedBridge registerAdditionalModuleClasses:modules];
RCTJavaScriptLoader
+ (void)loadBundleAtURL:(NSURL *)scriptURL onProgress:(RCTSourceLoadProgressBlock)onProgress onComplete:(RCTSourceLoadBlock)onComplete
|---NSData *data = [self attemptSynchronousLoadOfBundleAtURL:scriptURL
                                          runtimeBCVersion:JSNoBytecodeFileFormatVersion
                                              sourceLength:&sourceLength
                                                     error:&error];
|---onComplete(nil, RCTSourceCreate(scriptURL, data, sourceLength));

+ (NSData *)attemptSynchronousLoadOfBundleAtURL:(NSURL *)scriptURL
                               runtimeBCVersion:(int32_t)runtimeBCVersion
                                   sourceLength:(int64_t *)sourceLength
                                          error:(NSError **)error
|---FILE *bundle = fopen(scriptURL.path.UTF8String, "r");
    size_t readResult = fread(&header, sizeof(header), 1, bundle);
[RCTCxxBridge enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray *)args completion:(dispatch_block_t)completion]
|---

NSInvocation 调用 native 方法

调用原生代码生成UI控件

RCTUIManager RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag
                                 viewName:(NSString *)viewName
                                  rootTag:(nonnull NSNumber *)rootTag
                                    props:(NSDictionary *)props)
|---createViewBlock
      |---[RCTComponentData createViewWithTag:reactTag];
            |--- [self.manager view]
                 #此处self.manager是实际需要生成的UI类,如RCTTextView等
                 #所以,所有RN的原生UI都必须实现view功能
      |---RCTUIManager->_viewRegistry[reactTag] = preliminaryCreatedView;
          #保存至注册数组,reactTag:preliminaryCreatedView
          #RCTUIManager->_viewRegistry
          # {1 = "<RCTRootContentView: 0x7faf12c015d0; reactTag: 1; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x60000024eaf0>; layer = <CALayer: 0x6040002376c0>>";
          # 2 = "<UIView: 0x7faf12f0a6d0; frame = (0 0; 0 0); layer = <CALayer: 0x600000621300>>";}
Instance C++ 类
void Instance::loadRAMBundle(std::unique_ptr<RAMBundleRegistry> bundleRegistry,
                             std::unique_ptr<const JSBigString> startupScript,
                             std::string startupScriptSourceURL,
                             bool loadSynchronously)

RCTModuleMethod C++ 类
通过NSInvocation动态调用相应的OC模块方法

- (id)invokeWithBridge:(RCTBridge *)bridge
                module:(id)module
             arguments:(NSArray *)arguments
   [self processMethodSignature];   //set blocks
   block(bridge, index, RCTNilIfNull(json(arguments))   //set arguments
   [_invocation invokeWithTarget:module];   //调起函数
   [_invocation getReturnValue:&returnValue];   //获取返回值

RN 支持功能
tabbar,nagigator,text,image,数据库?,ar?,真机调试日志?,网络,摄像头拍照,图片剪裁,音频,视频,下载,

添加RN库

tabbar
官方组件 TabBarIOS,TabBarIOS.Item,只支持iOS,弃用
流行组件

原文地址:http://blog.51cto.com/7324086/2128523

时间: 2024-10-07 02:33:40

react native 0.50 源码解析 再出发 持续更新的相关文章

Vue源码阅读笔记,持续更新

/ / Vue.js v2.1.3 源码阅读记录 使用的文件为使用es2015的本地文件 2018年4月20日 14:06:30 */ 第一章,Vuejs的整体架构 1. 入口 入口处使用一个闭包(function (global,factory) {factory()})(this,factory): 其中factory是工厂的意思,它的内部实现是一个工厂函数,其中直接声明的function为私有成员. 2. 生命周期的理解 理解vue的生命周期对通读vue源码的效率有较好的帮助,它的生命周期

Percona 8.0 ThreadPool源码解析

ThreadPool的基本功能在Percona 8.0里面没有太大的变化,只不调用的方式有变化,这里只介绍threadpool插件的初始化过程和调用过程. threadpool本身的逻辑可以参考: MariaDB · 源码分析 · thread pool Percona 5.7线程池源码分析 threadpool插件初始化过 线程池默认是关闭的,要开启这个功能,需要启动实例时指定参数--thread-handling=pool-of-threads.这个参数在代码中对应的变量是Connectio

GNU GRUB 2.00 源码分析笔记,持续更新

前言 很多运维类书籍或文章仅从系统管理者的角度讲解了 grub 的安装以及使用, 本篇博文则从 gnu grub 2.00 的源码入手,从开发者,以及系统底层运行机制的角度,分析 grub 是如何作为跨平台的"全面统一的引导加载程序",来引导操作系统,加载 Linux 内核的过程等等, 部分内容参考了<深度探索 Linux 操作系统>一书中相关的内容(ISBN 978-7-11143901-1 )以及 gnu grub 项目官方站点的文档,并且加入自己分析源码时的笔记. (

Android 高级自定义Toast及源码解析

Toast概述 Toast的作用 不需要和用户交互的提示框. 更多参见官网:https://developer.android.com/guide/topics/ui/notifiers/toasts.html Toast的简单使用 Toast.makeText(MainActivity.this.getApplicationContext(),"沉迷学习,日渐消瘦",Toast.LENGTH_SHORT).show() 自定义Toast Toast customToast = new

【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源热更新 Android热更新开源项目Tinker源码解析系类之三:so热更新 转载请标明本文来源:http://www.cnblogs

Mahout推荐系统引擎UserCF中的IRStats部分源码解析

Mahout提供推荐系统引擎是模块化的,分为5个主要部分组成: 1. 数据模型 2. 相似度算法 3. 近邻算法 4. 推荐算法 5. 算法评分器 今天好好看了看关于推荐算法以及算法评分部分的源码. 以http://blog.csdn.net/jianjian1992/article/details/46582713 里边数据的为例进行实验. 整体流程的代码如下,依照上面的5个模块,看起来倒是很简单呀. public static RecommenderBuilder userRecommend

GlusterFS源码解析 —— GlusterFS日志解析

Logging.c: /* Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or

【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 Android热更新开源项目Tinker源码解析系类之三:so文件热更新 转载请标明本文来源:http://www.cnblogs.com/yyangblog/p/6252855.html更多内容欢迎star作者的github:https://github.com/LaurenceYang/artic

EventBus3.0源码解析

本文主要介绍EventBus3.0的源码 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递. EventBus使用简单,并将事件发布和订阅充分解耦,从而使代码更简洁. 本文主要从以下几个模块来介绍 1.EventBus使用 2.EventBus注册源码解析 3.EventBus事件分发解析 4.EventBus取消注册解析 一.EventBus使用 1.首先是注册 EventBus.getDefault().register(this)