React Native For Android 架构初探

作者:王少鸣

Facebook 在2015.9.15发布了 React Native for Android,把JavaScript 开发技术扩展到了Android平台。React Native 让开发者使用 JavaScript 和 React 编写应用,利用相同的核心代码就可以创建 基于Web,iOS 和 Android 平台的原生应用。本文将浅析Android React的架构及相关基础知识。 环境搭建及调试相关知识参考官网文档即可,本文不再赘述。

一.React架构分析

1.层次架构:

Java层:java层为逻辑入口,启动C++层的javascript解析器,执行js通过c++传递来的渲染指令,从而构建NativeUI等。java层依赖于众多优秀开源库,在图片处理使用的是Fresco,网络通信使用的是okhttp,当然还有众多工具类,如Json解析工具jackson,Animation知名开源库NineOldAndroids,小而全的底层工具类bolts等,在java层均封装为Module。java层核心jar包是react-native.jar,封装了众多上层的interface,如Module,Registry,bridge等,下面会以App的启用过程,完整分析java层的架构。

C++层:c++层最主要是封装了JavaScriptCore,执行对js的解析。基于JavaScriptCore,Web开发者可以尽情使用ES6的新特性,如class、箭头操作符等,而且 React Native运行在JavaScriptCore中的,完全不存在浏览器兼容的情况。Bridge桥接了java <> js 通信的核心接口。JSLoader主要是将来自assets目录的或本地file加载到javascriptCore,再通过JSCExectutor解析js文件。

Js层:主要处理事件分发及UI Layout,主要有以下几个部件:

  • Component:Js层通js/jsx编写的Virtual Dom来构建Component或Module,Virtual DOM是DOM在内存中的一种轻量级表达方式,可以通过不同的渲染引擎生成不同平台下的UI。component的使用在 React 里极为重要, 因为component的存在让计算 DOM diff 更高效。
  • Lifecycle&Data:React 组件通过内部的 state 变量控制生命周期及事件回调。如getInitialState方法用于定义组件初始状态,后续组件可通过 this.state 属性读取该状态。当事件触发(或者主动调用setState方法更新数据)导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,重新渲染组件。
  • Layout:React使用css-layout,css-layout使用javascript实现了flexbox ,不依赖于DOM,能编译成Object-C或者Java,最终达到跨平台的展示目的,但暂时不支持css3,暂时只能支持简单的布局和普通的动画。

2.Js与Java通信机制:

在Java层与Js层的bridge分别存有相同一份模块配置表,Java与Js互相通信时,通过bridge里的配置表将所调用模块方法转为{moduleID,methodID,args}的形式传递给处理层,处理层通过bridge的模块配置表找到对应的方法执行,如果有callback,则回传给调用层。在了解ReactAndroid APP启动后,第三部分会详细讲这套机制。

二.从应用启动到页面加载完成分析

上图为 Android React 加载过程的解析,下面先概要描述上层核心类及原理,再梳理核心的启用步骤。 Core Class: 1.ReactInstanceManager:主要是用来创建及管理Catalyst的实例的上层接口,控制开发调试,生命周期与ReactRootView所在activity保持一致。

2.ReactRootView:为启动入口核心类,负责监听及分发事件并重新渲染元素,App启动后,其将作为App的root view。

3.CatalystInstance:顶级异步JSCAPI封装类,提供Java与Js互通的环境,通过ReactBridge将Svr的Js Bundle传送到Js引擎。

4.NativeModuleRegistry:Java层模块注册表,即暴露给Js的API集合。

5.JavascriptModuleRegistry:Js层模块注册表,负责将所有JavaScriptModule注册到CatalystInstance,通过Java动态代理调用到Js。

6.CoreModulePackage:定义核心框架模块,创建NativeModules&JsModules。

启动过程的解析:

1.在ReactInstanceManager时会配置应用所需的java模块与js模块之后,通过ReactRootView的startReactApplication启动APP。

2.在创建ReactInstanceManager同时会创建用于加载JsBundle的JSBundlerLoader,并传递给CatalystInstance。

3.CatalystInstance会创建Java模块注册表及Javascript模块注册表,并遍历实例化模块。

4.CatalystInstance通过JSBundlerLoader向Node Svr请求Js Bundle,并传递给JSCJavaScriptExectutor,最后传递给javascriptCore,再通过ReactBridge通知ReactRootView完成渲染。

三.Js与Java通信机制

Java与Js之间的调用,是以两边存在两边存在同一份模块配置表,最终均是将调用转化为{moduleID, methodID,callbackID,args},处理端在模块配置表里查找注册的模块与方法并调用。 Java -> Js :Java通过注册表调用到CatalystInstance实例,透过ReactBridge的jni,调用到Onload.cpp中的callFunction,最后通过javascriptCore,调用BatchedBridge.js,根据参数{moduleID,methodID}require相应Js模块执行。详细流程如下图。

Js -> Java:JS不主动传递数据调用Java。在需要调用调Java模块方法时,会把参数{moduleID,methodID}等数据存在MessageQueue中,等待Java的事件触发,再把MessageQueue中的{moduleID,methodID}返回给Java,再根据模块注册表找到相应模块处理。详细流程如下图。

四.总结

React将UI分解成组件,废弃了模板,统一视图逻辑标签,使构建的视图更容易扩展和维护,Vitual Dom更是其提高性能的亮点,React 中的Dom并不保证马上影响真实的Dom,React会等到事件循环结束,利用diff算法,通过当前新Dom树与之前的Dom树作比较,计算出最小的步骤更新真实的DOM。 Android React的推出更使得利用相同的核心代码就可以创建 Web,iOS 和 Android 平台的原生应用,但目前Android React的HelloWorld基础库将近7m,落地项目仍需要精简,目前我们正在精简中。当然,对于Andriod版本也有考验,仅支持 Android 4.1 (API 16) 以上的版本(iOS 7.0),当然,在系统不支持情况下,H5可以作为后备方案。 我们后续会持续关注Android React的动态,向大家继续推送更多关于Android React的文章。(底部有关于Android React所有类库的描述)

文章来源公众号:qq空间终端开发团队(qzonemobiledev)

相关推荐

ReactNative For Android 框架启动核心路径剖析

ReactNative For Android 项目实战总结

面向未来的跨界开发技术(上)

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开源项目

码云周刊:当测试拿起自动化测试工具,开发仿佛看见一场悲剧正在上演!

类型:自动化测试 虽然之前小一做过几年开发,但当时对于在公司兴起的自动化测试概念还不是很清楚,觉得是一种很神秘的东西,后来通过向业内资深的测试工程师朋友咨询才恍...

3439
来自专栏更流畅、简洁的软件开发方式

【自然框架】之表单控件(一)实体类(Class)VS 字典(Dictionary)

用一个具体一点的例子来说一下,我实现单表的添加、修改的思路和方式,顺便和三层里的实体类的方式做一下对比。 一、我的拆分思想之一       简单的操作和复杂的操...

2118
来自专栏hotqin888的专栏

工程师对电子规范、图集和计算书的管理-EngineerCMS

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

682
来自专栏编程

改进异常处理的 6 条建议

来源:ImportNew - 唐尤华 , 合理地使用异常处理可以帮你节省数小时(甚至数天)调试时间。一个乘法异常会毁掉你的晚餐乃至周末计划。如果处置不及时,甚至...

2039
来自专栏架构之路

谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署

953
来自专栏机器学习从入门到成神

Pandas使用DataFrame进行数据分析比赛进阶之路(二):日期数据处理:按日期筛选、显示及统计数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

1481
来自专栏大数据钻研

欢迎来到HTML5.2时代!

21世纪,2016年6月,HTML 5.1从工作草案变为了候选标准。正如你了解的那样,这是将提案变为标准的第二步,Web的如此发展也将影响我们的日常生活。作为候...

2847
来自专栏张善友的专栏

无特性的 MEF 配置方法

Managed Extensibility Framework (MEF) 旨在为 Microsoft .NET Framework 开发人员提供一种简便的方法...

1935
来自专栏更流畅、简洁的软件开发方式

分页解决方案 之 QuickPager的使用方法(目录)

      QuickPager asp.net 2.0 分页控件,基本告一段落。现在把使用方法、源码、Demo公布一下,感兴趣的可以下载看看。 一、从提取数...

1879
来自专栏星流全栈

最新的15 个有趣的前端库(December 2016)

1313

扫码关注云+社区