React Native 手工搭建环境 之iOS篇
常识
React native 开发服务器
在开发时,我们的框架是这样的:

当正式发布进入到生产环境时,开发服务器上所有的js文件将会被编译成包的形式,直接嵌入到客户端内。这时,已经不再需要开发服务器的支持了。
npm
npm,全称是 node package manager,顾名思义最开始是作为 Node 的包管理器存在的。不过经过不断的发展和壮大,现在的 npm 早就不再局限于 Node 的范畴,已经成为 Javascript 的包管理器,看看下面的 npm
常见命令:
npm install -g react-native-cli
安装 react native 命令行搭建
React Native 命令行环境搭建困难
npm install -g react-native-cli
这是在从npm服务器上拉取react-native-cli。所以慢的原因便是因为npm服务器不在国内。聪明的国人已给出了解决办法,通过FQ来解决此问题。更高兴的是npm提供了一个register的属性,可以让开发者自由的设置镜像地址。开发者们最常用的便是淘宝的镜像地址。据统计国内比较常用的镜像地址有:
http://r.cnpmjs.org/
http://registry.npm.taobao.org/
http://registry.npmjs.eu/
http://registry.npmjs.org.au/
http://npm.strongloop.com/
https://registry.nodejitsu.com/
http://registry.npmjs.pt/
package.json 的文件结构
一个合格的 package.json 文件需要至少包含 name 和 version 两个字段,这两个字段组成的二元组可以唯一标识一个包,如下所示:
{
"name": "AwesomeProject",
"version": "0.0.1"
}
字段名 | 含义 | 示例 |
---|---|---|
name | 包名需要具备唯一性 | "name": "redux" |
version | 包的版本号,遵循语义化版本(http://semver.org/lang/zh-CN/)格式,也就是版本号包含三位:MAJOR.MINOR.PATCH。MAJOR 表示版本发生大的变化,例如 API 不兼容旧版本;MINOR 表示版本增加新功能,但是兼容旧版本的;PATCH 表示兼容旧版本的一些 bug 修复 | "version": "3.5.2" |
description | 项目的描述,尽量保持言简意赅 | "description": "Predictable state container for JavaScript apps" |
dependencies | 这个 Package 的生产依赖,当用户安装你的 Package 时会自动安装这些依赖 | "dependencies": { "react": "15.1.0", "react-native": "0.27.0-rc2" } |
private | 设置为 true 时,npm 将不会发布这个 Package,这个标记主要用来防止不小心发布某个内部使用的私有 Package 到公共的 npm registry | "private": true |
目前这些已经足够,如果需要更多,请查看此链接
初始化React Native环境
在我们要配置React Native环境的项目中,进入到*.xcodeproj
文件的上级目录,运行React Native初始化react-native init [Project Name]
。
这样会在ios目录下生成一个同名工程,接下来我们需要把这个同名工程的配置迁移到现有项目。
链接React Native的Libraries
查看ios目录下的那个同名工程,会看到这个工程引用的React Native库如下:

在开发过程中如果需要其他组件,也以相同方式加入到项目中。具体操作如下:
- 右键项目目录,选择New Group,新建一个名为Libraries的逻辑目录;
- 在node modules目录中找到$root_path/node_modules/react-native/Libraries,React Native的所有库都是以static library的形式提供;
- 将对应的.project文件拖入到Libraries逻辑目录下,效果如上图所示;
- 在Build Phase中link刚才添加的库; 
清理多余文件
删除ios/和android/下的文件,这些是init命令自动生成的。
- 出现问题1 :引入工程里要添加 -ObjC

应该如何做
node_modules
中包含两个部分代码, JS代码和原生代码(OC和Java). 实际上, 只有原生代码需要加入原生项目中编译, 而JS代码只用于打包bundle. 这样意味着, 我们可以将node_modules分成两个部分, 原生代码可以随原生项目的SVN/Git进行版本控制, 而JS部分可以通过npm的package.json
进行版本控制. 这样, 原生开发同学不需要下载node_modules, 也可以对RN的源码进行修改, 而RN开发同学也可以享受版本控制的好处.
具体步骤
- 步骤1
获取你所需要的RN版本(node_modules).
如在命令行输入react-native init AwesomeProject, 得到最新版的RN. 获取AwesomeProject中的package.json和node_modules. 将二者置于与原生项目文件夹平级的地方. 即与iOS和Android文件夹平级之处, 方便双平台使用.
- 步骤2
拷贝node_modules/react-native文件夹至原生项目中, iOS项目保留Libraries文件夹和React文件夹(安卓项目保留ReactAndroid文件夹). 其余所有删除.
- 步骤3
iOS项目, 创建Group,放置RN工程项目:
/node_modules/react-native/React/React.xcodeproj
/node_modules/react-native/Libraries/Text/RCTText.xcodeproj
/node_modules/react-native/Libraries/WebSocket/RCT WebSocket.xcodeproj
你需要用到哪些就加哪些. 全部加上也无妨.
- 步骤4
Build Rules中添加静态库文件.
如libRCTText.a等. libRCT开头的都加上.
- 步骤5
Build Settings添加循环依赖
在Targets-Build Settings-Header Search Paths中加入$(PROJECT_DIR)/项目名/ReactNative/react-native/React 这里要加入的是react-native/React文件夹的路径, 我的react-native文件夹位于项目名/ReactNative下,因此是这样写.
- 步骤6
设置Other Linker Flags
Targets-Build Settings-Other Linker Flags中加入-ObjC
- 步骤7
删除原生项目中步骤2拷贝过来的react-native文件夹中所有JS文件. 这步本可以和步骤2合为1步,单独列出的原因是: 如果没有删除其中的JS文件, 其中的JS代码@providesModuleprovide了很多Module, 会与你在步骤1中的node_modules中的代码冲突.
- 步骤8
删除启动node服务脚本.
打开步骤3中引入的RN工程项目:React.xcodeproj-Targets-Build Phases-Run Script. 删除启动node服务脚本的那个脚本. 即内容是
if nc -w 5 -z localhost 8081 ; then
if ! curl -s "http://localhost:8081/status" | grep -q "packager-status:running" ; then
echo "Port 8081 already in use, packager is either not running or not running correctly"
exit 2
fi
else
open "$SRCROOT/../packager/launchPackager.command" || echo "Can't start packager automatically"
fi的脚本
- 步骤9
随原生项目上传react-native文件夹, 此时react-native文件夹中只有原生代码, 可以进行版本控制;
修改package.json, 修改你需要的内容(如修改dependencies, 将某些组件固定在某个版本), 之后用package.json控制更新node_modules.
package.json也上传SVN, 大家共用这个管理node_modules.
- 步骤10
打开命令行, 进入与项目平级的目录(即node_modules所在目录), 输入npm start. 启动node服务.
打开XCode/Android Studio, 进入RN开发.
小细节
iOS真机调试, 需要将localHost改为本机的ip, 同时手机要与电脑处于同一wifi下.
如果要真机chrome debug, 要修改RCTWebSocketExecutor.m中setup函数的URLString的localHost.
Android真机调试就是adb reverse tcp:8081 tcp:8081