标签:
PS该报告偏向理论层面,技术层面由于本人才疏学浅属于前端小白因此暂时未作过多研究。
React Native是Facebook开发的一套框架,其目的在于使用JavaScript语言开发原生APP,目前iOS版本和Android版本均已开源。
下图摘自React Native官网首页:
翻译:
React Native使你能够基于javaScript和React开发世界级的原生APP,其焦点在于开发效率,因为你能够用它来开发多个平台的应用(包括iOS和Android)。换句话说:learn once, write anywhere. Facebook目前已经使用React Native开发了多个原生应用,并将持续完善这套框架。
可以看到,React Native框架本身的定位在于提升移动端应用开发效率。再看看一个“webView”打天下的Hybrid应用,React Native是否也能够一套代码实现两个平台的“一劳永逸”呢?虽然我觉得不能说完全否定,但是基本是不可行的。
官方对于React Native的描述是 learn once, write anywhere ,而并非是 write once,run anywhere. 也就是说,React Native的跨平台,指的是可以用React Native编写两个平台的应用,而不是一套React Native代码可以同时在两个平台上跑。原因在于React Native开发的是原生应用,iOS端和Android端的大部分控件是无法整合到同一个JS端组件或API上的。事实上,只有少数的组件及API能够垮平台使用。因此,简单地说,一个应用,依旧两套代码,只不过可以由一套框架(并不绝对)、一个RN团队来完成。
(以下对“React Native”或以“RN”简称)
说到RN的语法,不得不提到React(即React.js)。React同样是脸书开源的一套前端框架,核心语言javaScript毋庸置疑,另外其采用组件化的方式构建界面,这在语法上则需要HTML的支持;对于界面布局,采用的则是一贯的CSS方案。可能你要一脸懵逼了,心想这不就是大名鼎鼎的前端三剑客吗?是的!然而React将HTML、CSS、javaScript黑魔法般地整合到一起,自成规则,成就了一种全新的语法:JSX。而React Native采用的,正是React的这套语法。说白了,React+RN,JS一统三端了!另外,RN已经支持了ES6语法。
使用Node.js作为javaScript的运行环境,其内置了V8引擎。就作为一名RN开发者而言,对于Node的认识即便一片空白实际上也无伤大雅。
安装软件包管理工具 homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
安装node.js(或者从官方下载 node.js)
brew install node
安装watchman,watchman用来监视文件并且记录文件的改动情况
brew install watchman
安装flow(flow来为js代码加上类型检查,根据需要是否安装)
brew install flow
更新上述程序,保持最新版本(本人配置好环境后未执行该命令更新上述程序版本,工程运行报错,更新后运行正常)
brew update && brew upgrade
安装RN的命令行工具,通过npm安装
npm install -g react-native-cli
Ok,万事俱备!
通过命令行创建第一个RN工程learn_rn: react-native init learn_rn
运行完毕后会在当前目录创建一个 learn_rn 文件夹,这个就是RN工程所在的文件夹。
open learn_rn
工程目录如下:
回忆刚刚执行 react-native init learn_rn
是不是install了很长时间。原因有二。
现在,打开iOS文件夹,运行.xcodeproj工程文件,再熟悉不过的XCode界面。直接Run,最终模拟器会显示一个默认的界面。
分析一下从Run到界面加载的过程发生了什么,首先是JS端的启动工作:
接着是原生端的启动工作:
来对项目作一点小小的修改。打开index.ios.js文件,暂且不对源码作介绍。将源码中 “Welcome to React Native!” 修改成 “Hi!I’m Lotheve”,保存。 这个时候,打开模拟器,然后 Command+R
,神奇的事情发生了,界面瞬间刷新成修改后的效果。
前端程序猿估计要直呼大惊小怪了,然而对于一个没见过什么世面的原生程序猿,习惯了对任何源码的修改都要重新Run一次工程以适应修改,这样的体验简直要飞!揪其原因,很简单,js代码是跑在服务器上的,每次reload,服务器重新加载代码,实时刷新原生界面(事实上,并不是刷新整个UI,而是只刷新diff部分,这在下面将会介绍)
在刚才的介绍中有提到,RN的界面是通过一个RCTRootView对象显示的,这个RCTRootView是UIView的子类,因此很容易地可以在原生中嵌入React Native。具体步骤如下:
原生中,界面的更新往往由控制器来控制,RN则是通过“状态机”的机制来驱动UI更新的。RN中,整个UI是一个Component树,由一个个Component构成,最终被编译成一个虚拟DOM,加载到内存中。另外,每一个Component可以定义一种叫“state类型”的属性,当这种类型的属性值发生变化时,系统会定位到响应的DOM组件,并计算出DOM的diff信息,根据这个“diff”来驱动UI的更新。
RN的这种UI更新机制,保证了每次只刷新需要目标UI,避免的整个UI的刷新,从而保证了UI渲染的效率。React Native UI更新机制如下图:
对于一个RN应用程序,编码工作主要在RN端,因此RN与原生的通信主要探讨RN端如何实现JS调原生。
就iOS而言,React Native与原生之间的通信并不是采用JavaScriptCore提供的可以让两者互调的一些方法(例如webView的stringByEvaluatingJavaScriptFromString、通过获取JSContext交互、以及拦截协议等 PS本人已知的就这么多),而是在此基础上自己实现了一种机制,这套机制能够通用于所有JS引擎上,从而与安卓的V8引擎形成了一种通用的机制。
关于React Native通信机制,bang的这篇博客个人觉得已经分析得非常到位,我就说一下我对React Native通信机制的简单理解。
RN中JS调原生主要是采用了一种叫“模块配置表”的东西,它本质是一个json文件。原生暴露给JS的类及方法,称之为模块类和模块方法。在模块配置表中,保存了这些模块类的集合以及类中模块方法对应的的集合。这个模块配置表会分别保存一份在iOS端和JS端,当JS调用原生的某个方法时,从JS端的模块配置表中找到对应的模块类id和模块方法id,然后传递给iOS端,从iOS端的模块配置表中还原出对应的原生方法调用之。
简单的流程如上所述,如果要回调,只不过是JS端多传了一个回调id给iOS,iOS执行完毕相应的方法之后会回传回调id给JS端,由JS端执行实现保存的JS回调代码。另外关于JS端是如何将id传递给iOS的,这个问题在bang的博客里有说明,说是采用事件响应的机制,个人不是很理解,猜测是原生在JS线程中通过NSTimer事件不断调用JS,通过将id以返回值的形式传给JS。
下面附上大神博客中给出的调用流程图:
优点:
缺点:
做不到 Write once, Run everywhere,也就是说开发者依然需要为 iOS 和 Android 平台提供两套不同的代码,比如参考官方文档可以发现不少组件和API都区分了Android和iOS版本。即使是共用组件,也会有平台独享的函数。
由于 Objective-C 与 JavaScript 之间切换存在固定的时间开销,所以性能必定 不及原生。比如目前的官方版本无法做到 UItableview(ListView) 的视图重用,因为滑动过程中,视图重用需要在异步线程中执行,速度太慢。这也就导致随着 Cell 数量的增加,占用的内存也线性增加。
由于RN版本目前还处于萌芽期,版本更新那叫一个快。然而有的迭代更新,会将部分支持老版本的代码在新版本中废除,使得原先开发的APP在版本迭代之后运行直接崩溃。这个问题目前无解,你根本就无法预测下一版本会做什么修改,而只能去适应修改!除非你永远不需要更新你的应用!
官方对版本迭代的说明是每两个星期更新一次,目前官方official版本为0.29(当前时间2016.7.13)
RN是面向前端开发人员提供的移动端开发框架,个人认为其,对于不懂前端技术的移动开发者来说,学习RN还是有很大学习成本的。
尽管npm提供了大量的RN组件或者API,但是万一现有代码包无法满足实际需求,就要自己定制原生模块,通过桥接的方式在RN中使用。因此RN开发不能做到完全屏蔽iOS端或Android的技能,开发者必须对原生平台有所了解。这样看来,要想吃透RN,几乎是通吃3个端了,学习成本是非常高的。
RN的诞生,不过是给web开发者向移动进军提供了桥梁,对于移动开发者,我认为并未有太大吸引力,至少对于我而言如此。
标签:
原文地址:http://blog.csdn.net/lotheve/article/details/51900867