402's Dojo

React Native入门实例教程 - 从现有项目迁移

最近一段时间在学习和实践React Native,做一些有趣有用总结和大家分享。这个系列文章可以在这里找到。
Facebook官方提供的迁移方式适合于简单的项目,并且没有运行react-native init命令构建的项目的一些自动化配置。于是摸索了一下适合于大型复杂项目的迁移方式。

集成React Native库方式的选择

官方推荐的迁移方式是通过CocoaPods来管理需要的React Native库(不止一个)。但由于既有项目的结构可能比较复杂,所以也可以直接引入源码自己配置环境。本文采用自己配置的方式,如果既有项目结构允许用CocoaPods配置的话还是推荐CocoaPods

在现有项目中集成React Native

项目结构

我们先来回顾一下执行react-native init命令创建的项目结构,现有项目配置之后也希望与之相同。

项目名为firststep,和项目相关的代码文件存储在firststep目录下:

  • ios: iOS项目相关代码,就是普通iOS开发中在Xcode运行的一坨东西;
  • android:同理android项目相关代码;
  • index.ios.js: ios平台加载的JS脚本;
  • index.android.js:android平台加载的JS脚本;
  • package.json:把当前项目作为npm package的配置文件;内容如下:
{
"name": "firststep",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start"
},
"dependencies": {
"react-native": "^0.15.0"
}
}

初始化React Native环境

在我们要配置React Native环境的项目中,进入到*.xcodeproj文件的上级目录,运行React Native初始化react-native init [Project Name]

prompt先输入yes,这样会在ios目录下生成一个同名工程,接下来我们需要把这个同名工程的配置迁移到现有项目。

友情提示:init过程可能会有一点慢,也没有提示,需要耐心等一下。

链接React Native的Libraries

查看ios目录下的那个同名工程,会看到这个工程引用的React Native库如下:

默认项目中链接了这么多库,我们暂时可能用这么多。在开发过程中如果需要其他组件,也以相同方式加入到项目中。具体操作如下:

  1. 右键项目目录,选择New Group,新建一个名为Libraries的逻辑目录;
  2. 在node modules目录中找到$root_path/node_modules/react-native/Libraries,React Native的所有库都是以static library的形式提供;
  3. 将对应的.project文件拖入到Libraries逻辑目录下,效果如上图所示;
  4. Build Phase中link刚才添加的库;

编译前执行React Native shell脚本

React Native的iOS项目在编译时会先运行一个shell脚本,其作用有两个:

  • 从Terminal启动了一个Node.js的server用于React Native调试;
  • 将React Native的资源文件打包放在编译目录下。
    具体添加方式是:
  • 点击Build Phase界面左上角的+号,
  • 添加一个Run Script Phase
  • 指定开始编译时运行shell脚本:node_modules/react-native/packager/react-native-xcode.sh
  • 注意:根据当前项目的根目录(project文件所在目录)配置node_modules的位置。

    解释一下这个脚本,脚本内容如下:
case "$CONFIGURATION" in
Debug)
DEV=true
;;
Release)
DEV=false
;;
"")
echo "$0 must be invoked by Xcode"
exit 1
;;
*)
echo "Unsupported value of \$CONFIGURATION=$CONFIGURATION"
exit 1
;;
esac
# Xcode project file for React Native apps is located in ios/ subfolder
cd ..
set -x
DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
# Define NVM_DIR and source the nvm.sh setup script
[ -z "$NVM_DIR" ] && export NVM_DIR="$HOME/.nvm"
if [[ -s "$HOME/.nvm/nvm.sh" ]]; then
. "$HOME/.nvm/nvm.sh"
elif [[ -x "$(command -v brew)" && -s "$(brew --prefix nvm)/nvm.sh" ]]; then
. "$(brew --prefix nvm)/nvm.sh"
fi
react-native bundle \
--entry-file index.ios.js \
--platform ios \
--dev $DEV \
--bundle-output "$DEST/main.jsbundle" \
--assets-dest "$DEST"
  • react-native bundle:这个脚本其实只是执行了最后一行的bundle命令;
  • CONFIGURATION部分从Xcode运行shell的参数中获取当前的编译环境(Build Configuration);
  • cd ..:值得特殊注意的是:由于默认项目位置在ios/AwsomeProject.xcodeproj目录下,因此需要先调到上级目录执行,否则取到的参数可能发生错误。如果你的目录结构与默认项目不同,则需要根据实际情况修改这行脚本,或者移动project文件到适当位置。例如project文件和node_moduels等配置文件在统一目录下则直接注释掉这一行,直接在当前目录执行后续命令即可。
  • DEST:取的是编译后App的目录位置,运行bundle生成的main.jsbundle和assets文件都放到这个目录下;
  • nvm:nvm这个部分最终执行了nvm.sh这个文件,启动一个Node.js的server在8081端口;
  • 最后一行在cd进入或者当前目录下运行react-native bundle命令,命令的具体参数解释请看这里

还遇到一件诡异的事情是,假如说我们在本次运行项目的时候,不希望执行这个sh脚本,在Xcode配置中将它注释掉了。那么注释sh脚本的修改只有重新打开这个Xcode项目后,脚本的修改才生效,当次编译运行还是会运行这个脚本。推测可能是Xcode做了缓存,有了解原因的朋友请留言指教~
此时运行项目即可看到从Terminal启动了一个Node.js的server,并且在DEST目录下生成了jsbundle文件。

清理多余文件

删除ios/android/下的文件,这些是init命令自动生成的。

特别是ReactAndroid目录下的assert.h会导致Xcode编译不过,删掉这个目录即可。


到此现有项目的迁移工作和React Native库集成已经完成,但是我们还没有具体的功能页面,接下来的文章会介绍。

React Native开发基本流程

现有项目迁移到React Native之后的基本开发流程大致如下,后续的文章也会根据这几部分来写,大家可以提前熟悉一下。

  1. 运行react-native init初始化环境;
  2. 改造现有项目;
  3. 利用React Native本地server进行功能的调试开发;
  4. react-native bundle生成jsbundle文件;
  5. 修改项目中引用的jslocation=的代码;
  6. 将引用了jsbundle文件的项目打包发布。

参考意见

  1. 查看React Native的项目结构会发现node_modules目录,包含的是React Native js文件运行的一些依赖库,类似于Ruby的gems,如果不经常变化建议上传到版本控制工具上,这样团队其他成员更新项目之后就不需要运行npm install再次配置。

可能用到的小技巧

  1. Xcode sh脚本Log查看:脚本中echo打印出的log可以在Xcode的Navigator->Report Navigator(快捷键:cmd+8)中查看到。
  2. 如果你的项目配置是用xcconfig文件配置的,那么xcconfig文件递归方式读取headers的方式如下:"$(SRCROOT)/../node_modules/react-native/React"/**,即增加/**

Where to go

React Native入门实例教程 - 一个完整的React Native例子

参考链接

评论