React Native原理篇整理笔记

开篇

  • 实现iOS动态化本质:某网友总结的只要具备如下几点就可以实现脚本语言本地语言互通
    • 本地语言有一个runtime机制可以动态解析对象的方法,并进行调用
    • 本地语言一定有一个脚本的解析引擎,iOS中对应的是JavaScriptCore
    • 建立一个脚本语言本地语言映射表KEY脚本语言认识的符号,VALUE本地语言认识的符号,通过这个映射表来完成从脚本语言本地语言的转换

基本概念

  • Facebook为什么取名叫React Native?你有想过这个问题吗?
  • 关于React的相关说明:
    • React是由Facebook推出的一个JavaScript框架,主要用于前端开发;
    • React只会局部刷新,因为有独创的Virtual DOM机制
    • Virtual DOM是一个存在于内存中的JavaScript对象,它与DOM(每个html界面可以看做一个DOM)是一一对应的关系,当界面发生变化时,React会利用DOM Diff算法,只对有变化的DOM进行刷新;
    • React是采用JSX语法,一种JS语法糖,方便快速开发;
  • 关于Native的相关说明:
    • 五种常见的开发模式:Native AppWeb AppHybrid AppWeexReact Native
    • Native App:原生开发
      • 优点:性能最高
      • 缺点:开发成本高,更新不是很便捷
    • Web App:整个App都是网页
      • 优点:用户不需要安装,类似微信小程序那种,适合创业公司快速试错
      • 缺点:用户体验不好,不能离线访问
    • Hybrid App:混合开发模式,原生Api+Html共同开发
      • 优点:界面复用性强,一个界面iOS和安卓都可以使用
      • 缺点:相对于原生,性能相对有所下降
    • Weex:基于Vue.js(JS框架)开发的App
      • 优点:
        • 可以做到一套代码,跨平台运行,通过runtime会自动把JS代码解析成对应平台(iOS/安卓)的原生API本质还是原生开发
        • 跳过App Store审核,远程更新代码,提高迭代频率和效率,既有Native的体验,又保证了开发效率
      • 缺点:开源较晚,互联网上相关资料还比较少,学习成本也不小,性能相对原生稍差,不过可以忽略不计,逼近利大于弊
    • React Native:基于React(JS框架)开发的App
      • 优点:
        • 跨平台开发,通过runtime会自动把JS代码解析成对应平台(iOS/安卓)的原生API本质还是原生开发
        • 跳过App Store审核,远程更新代码,提高迭代频率和效率,既有Native的体验,又保证了开发效率
      • 缺点:学习成本也不低,性能相对原生稍差,不过可以忽略不计,逼近利大于弊
    • WeexReact Native区别
      • Weex只要写一套代码,就可以运行在iOS/安卓平台上
      • React Native需要iOS/安卓都写,说明React Native底层解析原生API是分开实现的,即:iOS和安卓各一套
      • React Native相对来说要比Weex开源的早,稍微成熟一些,所以现在用React Native的公司还是多些

React Native把React转化为原生API的简单说明

  • React Native会在一开始生成OC模块表,然后把这个模块表传入JS中,JS参照模块表,就能间接调用OC的代码
  • 形象比喻:比如你买了一个机器人(OC),厂家会给你提供一份说明书(模块表)用户(JS)根据说明书(模块表)机器人(OC)发出操作指令

React Native是如何做到JS和OC交互

  • 本质:JS和OC交互得益于iOS原生API中有个JavaScriptCore框架,这里推荐一篇JavaScriptCore框架分析的文章
  • 大致实现原理
    • 首先写好JSX代码
    • Facebook封装的引擎会将把JSX代码解析成javaScript代码
    • javaScript代码读取出来,利用JavaScriptCore执行
    • 执行完毕后会返回一个数组,数组中包含:OC对象OC对象的属性OC对象所需执行的方法,至此完成了React转化为原生API的操作

React Native在iOS这边的启动流程

  • 创建RCTRootView,设置为窗口根控制器的View
  • 创建RCTBridge桥接对象,用于管理JS和OC交互
  • 创建RCTBatchedBridge批量桥接对象,JS和OC交互具体实现都在这个类中
  • 执行[RCTBatchedBridge loadSource],用于加载JS源码
  • 执行[RCTBatchedBridge initModulesWithDispatchGroup],用于创建OC模块表
  • 执行[RCTJSCExecutor injectJSONText],用于将OC模块表注入到JS中
  • 执行完JS代码,回调OC中的组件,完成UI渲染

React Native在iOS中加载JS源码的流程

// 加载【远程】服务器中JS代码
[RCTJavaScriptLoader loadBundleAtURL];

// 开启【异步】加载JS代码,这是一个【C函数】
attemptAsynchronousLoadOfBundleAtURL(NSURL *scriptURL, RCTSourceLoadProgressBlock onProgress, RCTSourceLoadBlock onComplete)

// 让批量桥接对象执行JS代码
[RCTBatchedBridge executeSourceCode:sourceCode];
// 内部真正执行JS代码的是【RCTJSCExecutor对象】
[RCTJSCExecutor executeApplicationScript];

// JS代码【执行完成】后发送通知【RCTJavaScriptDidLoadNotification】
[postNotificationName:RCTJavaScriptDidLoadNotification]

// RCTRootView监听到【RCTJavaScriptDidLoadNotification】通知后创建RCTRootContentView
// 然后获取RCTBridge中的RCTUIManager,用于注册RCTRootView,并且记录RCTRootView(管理UI组件)、_viewRegistry(保存所有注册的View)

// 通知JS运行App
[RCTRootView runApplication:bridge]

// 通过桥接对象让JS调用【AppRegistry】
[RCTBridge enqueueJSCall:@"AppRegistry" 
                  method:@"runApplication" 
                    args:@[moduleName, appParameters] 
              completion:NULL]

// 通过批量桥接让JS执行【AppRegistry】方法
[RCTBatchedBridge _actuallyInvokeAndProcessModule:module 
                                           method:method 
                                        arguments:args 
                                            queue:RCTJSThread]

// 让RCTJSCExecutor调用JS代码
[RCTJSCExecutor _executeJSCall:bridgeMethod 
                     arguments:@[module, method, args] 
                  unwrapResult:unwrapResult 
                      callback:onComplete]

// 执行完JS代码,会返回一个数组,OC需要做的事情都会保存到这个数组中
[RCTBatchedBridge _processResponse:json error:error]

// 处理JS返回的数组,包含(module,method,arguments)
[RCTBatchedBridge handleBuffer]

// 遍历数组,依次执行原生方法
[self callNativeModule:[moduleIDs[index] integerValue]
                method:[methodIDs[index] integerValue]
                params:paramsArrays[index]];

// 注意:当前某个方法,在遍历数组时的代码块中执行,不仅仅执行一次

React Native在iOS中的UI控件渲染流程

// 通知JS运行App
[RCTRootView runApplication:bridge]

// 执行完JS代码返回的响应,包含需要添加多少子控件等信息
[RCTBatchedBridge _processResponse:json error:error]

// 批量桥接对象调用批量处理完成方法
[RCTBatchedBridge batchDidComplete]

// 调用批量处理完成的方法,就会开始去加载rootView的子控件
[RCTUIManager batchDidComplete]

// 通过JS执行OC代码,让UI管理者创建子控件View
[RCTUIManager createView:viewName:rootTag:props]

// 通过【RCT_EXPORT_METHOD】宏定义createView这个方法
// RCT_EXPORT_METHOD宏:会在JS中生成对应的OC方法,这样JS就能直接调用
// 注意每创建一个UIView,就会创建一个RCTShadowView,与UIView一一对应
// RCTShadowView:保存对应UIView的布局和子控件,管理UIView的加载
RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag
             viewName:(NSString *)viewName
             rootTag:(__unused NSNumber *)rootTag
             props:(NSDictionary *)props)

// 布局RCTRootView、增加子控件
[RCTUIManager _layoutAndMount]

// 给RCTRootView对应的RCTRootShadowView设置子控件
// 注意:此方法也是JS调用OC方法
[RCTUIManager setChildren:reactTags:]

// 遍历子控件数组,给RCTRootShadowView插入所有子控件
[RCTRootShadowView insertReactSubview:view atIndex:index++]

// 处理保存在RCTShadowView中属性,就会去布局RCTShadowView对应UIView的所有子控件
[RCTShadowView processUpdatedProperties:parentProperties:]

// 给原生View添加子控件
[RCTView didUpdateReactSubviews]

// 至此完成UI渲染

React Native在iOS中的事件处理流程

// 在创建【RCTRootContentView】的时候,内部会创建【RCTTouchHandler】
// RCTTouchHandler继承【UIGestureRecognizer】,也就是它就是一个手势
// RCTTouchHandler内部实现了touchBegin等触摸方法,用来处理触摸事件
// 在创建RCTTouchHandler的时候,内部会创建RCTEventDispatcher
// RCTEventDispatcher用来把事件处理传递给【JS的方法处理】,也就是当UI界面产生事件,就会执行JS的代码处理
// 通过RCTRootContentView截获点击事件,会触发RCTRootContentView中的RCTTouchHandler对象
// 当产生事件的时候,会执行[RCTTouchHandler touchBegin]
// RCTTouchHandler的touch方法,会执行[RCTTouchHandler _updateAndDispatchTouches:eventName:],内部会创建RCTTouchEvent事件对象

// 让事件分发对象调用发送事件对象,内部会把事件保存到_eventQueue(事件队列中)
[RCTEventDispatcher sendEvent:event]

// 让事件分发对象冲刷事件队列,就是获取事件队列中所有事件进行执行
[RCTEventDispatcher flushEventsQueue]

// 遍历事件队列,一个一个分发事件,分发事件的本质:就是去执行JS的代码的相应事件
[RCTEventDispatcher dispatchEvent:event]

// 让桥架对象调用JS处理事件,本质:就是产生事件调用JS代码
[RCTBatchedBridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]];

// 这样就能完成把UI事件交给JS代码相应

参考资料

  • React Native从源码一步一步解析它的实现原理
  • React Native源码中JavaScriptCore详解

你可能感兴趣的:(React Native原理篇整理笔记)