开发平台:macOS
搭建开发环境
- 必需软件
Homebrew, Mac系统的包管理器,用于安装NodeJS和一些其他必需的工具软件。
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Node.js,一种javascript的运行环境,能够使得javascript脱离浏览器运行。
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
Node.js 的包管理器 npm(Node Package Manager),是全球最大的开源库生态系统。
$ brew install node
Yarn,Facebook提供的替代npm的工具,可以加速node模块的下载。
$ brew install yarn
或$ npm install -g yarn
react-native-cli,React Native轻量级的命令行工具,用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
$ npm install -g react-native-cli
Xcode7.0 或更高版本
- 推荐安装
Watchman是由Facebook提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager可以快速捕捉文件的变化从而实现实时刷新)。译注:此工具官方虽然是推荐安装,但在实践中,我们认为此工具是必须安装,否则可能无法正常开发。
brew install watchman
Flow是一个静态的JS类型检查工具。译注:你在很多示例中看到的奇奇怪怪的冒号问号,以及方法参数中像类型一样的写法,都是属于这个flow工具的语法。这一语法并不属于ES标准,只是Facebook自家的代码规范。所以新手可以直接跳过(即不需要安装这一工具,也不建议去费力学习flow相关语法)。
brew install flow
Nuclide是由Facebook提供的基于atom的集成开发环境,可用于编写、运行和 调试React Native应用。
但是推荐使用WebStorm或Sublime Text或Visual Studio Code来编写React Native应用。所有这些开发工具都是跨平台的。其中webstorm是收费的(勤劳的人自然免费了),体量较大,功能较多,基本无需配置,必然是首选。其他工具免费,相对轻量,但或多或少需要下载插件和配置。
react-native init AwesomeProject
cd AwesomeProject
react-native run-ios
可以使用--version
参数(注意是两个杠)创建指定版本的项目。例如$ react-native init MyApp --version 0.44.3
。注意版本号必须精确到两个小数点。
可以使用--simulator
参数指定模拟器。例如$ react-native run-ios --simulator "iPhone X"
查看使用帮助:
$ react-native --help
Scanning folders for symlinks in /Users/mxr/Desktop/XDS/RN/AwesomeProject/node_modules (12ms)
Usage: react-native [options] [command]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
start [options] starts the webserver
run-ios [options] builds your app and starts it on iOS simulator
run-android [options] builds your app and starts it on a connected Android emulator or device
new-library [options] generates a native library bridge
bundle [options] builds the javascript bundle for offline use
unbundle [options] builds javascript as "unbundle" for offline use
eject [options] Re-create the iOS and Android folders and native code
link [options] [packageName] links all native dependencies (updates native build files)
unlink [options] <packageName> unlink native dependency
install [options] <packageName> install and link native dependencies
uninstall [options] <packageName> uninstall and unlink native dependencies
upgrade [options] upgrade your app's template files to the latest version; run this after updating the react-native version in your package.json and running npm install
log-android [options] starts adb logcat
log-ios [options] starts iOS device syslog tail
dependencies [options] lists dependencies
info [options] Get relevant version info about OS, toolchain and libraries
$ react-native run-ios --help
Scanning folders for symlinks in /Users/mxr/Desktop/XDS/RN/AwesomeProject/node_modules (12ms)
react-native run-ios [options]
builds your app and starts it on iOS simulator
Options:
--simulator [string] Explicitly set simulator to use (default: iPhone 6)
--configuration [string] Explicitly set the scheme configuration to use
--scheme [string] Explicitly set Xcode scheme to use
--project-path [string] Path relative to project root where the Xcode project (.xcodeproj) lives. The default is 'ios'. (default: ios)
--device [string] Explicitly set device to use by name. The value is not required if you have a single device connected.
--udid [string] Explicitly set device to use by udid
--no-packager Do not launch packager while building
--verbose Do not use xcpretty even if installed
--port [number] (default: 8081)
--config [string] Path to the CLI configuration file
-h, --help output usage information
Example usage:
Run on a different simulator, e.g. iPhone 5:
react-native run-ios --simulator "iPhone 5"
Pass a non-standard location of iOS directory:
react-native run-ios --project-path "./app/ios"
Run on a connected device, e.g. Max's iPhone:
react-native run-ios --device "Max's iPhone"
Run on the AppleTV simulator:
react-native run-ios --simulator "Apple TV" --scheme "helloworld-tvOS"
$ react-native run-android --help
Scanning folders for symlinks in /Users/mxr/Desktop/XDS/RN/AwesomeProject/node_modules (12ms)
react-native run-android [options]
builds your app and starts it on a connected Android emulator or device
Options:
--install-debug
--root [string] Override the root directory for the android build (which contains the android directory) (default: )
--flavor [string] --flavor has been deprecated. Use --variant instead
--variant [string]
--appFolder [string] Specify a different application folder name for the android source. (default: app)
--appId [string] Specify an applicationId to launch after build. (default: )
--appIdSuffix [string] Specify an applicationIdSuffix to launch after build. (default: )
--main-activity [string] Name of the activity to start (default: MainActivity)
--deviceId [string] builds your app and starts it on a specific device/simulator with the given device id (listed by running "adb devices" on the command line).
--no-packager Do not launch packager while building
--port [number] (default: 8081)
--config [string] Path to the CLI configuration file
-h, --help output usage information
Simulator Screen Shot - iPhone X - 2018-04-19 at 14.43.16.png
- 设置项目目录结构
首先创建一个空目录用于存放React Native项目
创建一个/ios
子目录,把你现有的iOS项目拷贝到/ios
子目录中
创建一个/android
子目录,把你现有的Android项目拷贝到/android
子目录中
|-- AwesomeProject // 根目录
|-- android // 安卓项目
|-- ios // iOS项目
|-- package.json // JavaScript依赖包配置文件
|-- index.android.js // React Native应用在iOS上的入口文件
|-- index.ios.js // React Native应用在Android上的入口文件
- 配置package.json
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "^16.3.1",
"react-native": "^0.55.3"
}
}
示例中的version
字段没有太大意义(除非你要把你的项目发布到npm仓库)。
scripts
中是用于启动packager服务的命令($ npm start
命令则是启动开发服务器,其实$ react-native start
也是一样的)。
dependencies
中的react和react-native的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用npm info react
和npm info react-native
来查看当前的最新版本。
另外,react-native对react的版本有严格要求,高于或低于某个范围都不可以。
本文无法在这里列出所有react native和对应的react版本要求,只能提醒读者先尝试执行npm install
,然后注意观察安装过程中的报错信息,例如require react@某.某.某版本, but none was installed
,然后根据这样的提示,执行npm i -S react@某.某.某版本
。
如果你使用多个第三方依赖,可能这些第三方各自要求的react版本有所冲突,此时应优先满足react-native所需要的react版本。其他第三方能用则用,不能用则只能考虑选择其他库。
- 安装 React & React Native & 第三方依赖
请打开一个终端/命令提示行,进入到项目目录中(即包含有package.json文件的目录),然后运行下列命令来安装:
$ npm install
或 $ yarn add react-native
终端可能会打印类似如下的语句
react-native@0.54.4 requires a peer of react@^16.3.0-alpha.1 but none was installed.
只需要安装上述所需的react模块即可:
$ yarn add react@version_printed_above
这些模块会被安装到项目根目录下的node_modules/
目录中(所有通过npm install
命令安装的模块都会放在这个目录中。这个目录我们原则上不复制、不移动、不修改、不上传,随用随装)。通常我们需要将node_modules/
添加到.gitignore
忽略文件中。
使用 CocoaPods 导入 React Native
- 安装CocoaPods
CocoaPods是针对iOS和Mac开发的包管理工具。我们用它来把React Native框架的代码下载下来并添加到你当前的项目中。 我们建议使用Homebrew来安装CocoaPods。
$ brew install cocoapods
从技术上来讲,我们完全可以跳过CocoaPods,但是这样一来我们就需要手工来完成很多配置项。CocoaPods可以帮我们完成这些繁琐的工作。
- 配置CocoaPods的依赖
React Native框架整体是作为node模块安装到项目中的。下一步我们需要在CocoaPods的Podfile
中指定我们所需要使用的组件。
在你开始把React Native集成到你的应用中之前,首先要决定具体整合的是React Native框架中的哪些部分。而这就是subspec
要做的工作。在创建Podfile
文件的时候,需要指定具体安装哪些React Native的依赖库。所指定的每一个库就称为一个subspec
。
可用的subspec
都列在node_modules/react-native/React.podspec
中,基本都是按其功能命名的。一般来说你首先需要添加Core
,这一subspec
包含了必须的AppRegistry
、StyleSheet
、View
以及其他的一些React Native核心库。如果你想使用React Native的Text
库(即<Text>
组件),那就需要添加RCTText
的subspec
。同理,Image
需要加入RCTImage
,等等。
我们需要在Podfile文件中指定所需的subspec。创建Podfile的最简单的方式就是在/ios子目录中使用CocoaPods的init命令:
$ pod init
Podfile会创建在执行命令的目录中。你需要调整其内容以满足你的集成需求。调整后的Podfile的内容看起来类似下面这样:
# Uncomment the next line to define a global platform for your project
platform :ios, '8.0'
# The target name is most likely the name of your project.
target 'NumberTileGame' do
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks
# use_frameworks!
# Pods for NumberTileGame
# Your 'node_modules' directory is probably in the root of your project,
# but if not, adjust the `:path` accordingly
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
# Add any other subspecs you want to use in your project
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
# Third party deps podspec link
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
target 'NumberTileGameTests' do
inherit! :search_paths
# Pods for testing
end
end
创建好了Podfile后,就可以开始安装React Native的pod包了。
$ pod install
常见问题&解决方案
问题一
[!] Unable to satisfy the following requirements:
- `React/Core (from `../node_modules/react-native`)` required by `Podfile`
Specs satisfying the `React/Core (from `../node_modules/react-native`)` dependency were found, but they required a higher minimum deployment target.
在Podfile中添加指定最低为8.0的开发版本:platform :ios, '8.0'
问题二
[!] Unable to find a specification for `boost-for-react-native` depended upon by `Folly`
执行$ pod update
更新pods库即可。
- pod install & pod update & pod repo update 加速技巧
使用$ pod repo
查看本地的master库
$ pod repo
aliyun
- Type: git (master)
- URL: https://github.com/aliyun/aliyun-specs.git
- Path: /Users/MountainX/.cocoapods/repos/aliyun
lunboPodWSpec
- Type: git (master)
- URL: https://github.com/DevaLee/lunboPodWSpec.git
- Path: /Users/MountainX/.cocoapods/repos/lunboPodWSpec
Specs
- Type: git (master)
- URL: https://github.com/CocoaPods/Specs.git
- Path: /Users/MountainX/.cocoapods/repos/Specs
3 repos
使用$ pod repo remove NAME
来移除不要的master库
$ pod repo remove master
$ pod repo add master https://gitcafe.com/akuandev/Specs.git //添加pod的repo源
$ pod repo update
加速方法:进入到repos目录下,通过git clone
直接添加到master库,命令行如下:
$ cd ~/.cocoapods/repos
$ pod repo remove master
$ git clone https://github.com/CocoaPods/Specs.git master
首先要把本地老的master分支给移除掉,然后使用git clone从github镜像源上clone一份且设置本地master库。这样本地的repo就是最新的了。
$ git clone https://github.com/CocoaPods/Specs.git master
Cloning into 'master'...
remote: Counting objects: 2067512, done.
remote: Compressing objects: 100% (177/177), done.
remote: Total 2067512 (delta 78), reused 35 (delta 35), pack-reused 2067295
Receiving objects: 100% (2067512/2067512), 529.53 MiB | 95.00 KiB/s, done.
Resolving deltas: 100% (1164658/1164658), done.
Checking out files: 100% (230184/230184), done.
此时再进入到当前工程目录下,执行下面的命令行
$ pod install --no-repo-update --verbose
$ pod update --no-repo-update --verbose
其中--verbose
的作用就是打印出执行过程中详细的信息,--no-repo-update
的作用就是禁止更新repo,这样就避免执行了git fetch
,从而加快速度。
这样就解决了工程依赖的第三方库版本过低需要更新的问题。
但是我们在clone github镜像源的时候,发现速度还是比较慢的,这是因为国内访问github的速度不给力,没办法的事情,这个时候可以考虑挂一个VPN或者使用国内一些网站提供的镜像源。
目前搜集到的可选源有:
https://gitcafe.com/akuandev/Specs.git
http://git.oschina.net/akuandev/Specs.git
https://git.coding.net/hging/Specs.git
其实就是常见的git托管站
比如换成coding提供的一个镜像源,命令行如下:
$ cd ~/.cocoapods/repos
$ pod repo remove master
$ git clone https://git.coding.net/hging/Specs.git master
这样在clone的时候会发现速度很快哈。
另外,在自己工程中的Podfile文件加入下面一行描述:
source 'https://git.coding.net/hging/Specs.git'
如果不加这一句话,它默认还是从github镜像源地址去下载的,这个不要给忘记了。
注意
- master repo里面存放的是所有第三方库的地址列表,下载第三方库对应的源码还是要到指定的源码存放地址(podspecs中有指定)去下载。更换repo源只是加快了repo的下载速度,并不会加快第三方库源码的下载速度,两者是没有任何关系的。
- 在工程中尽量避免直接使用pod update、pod install,在后面添加--no-repo-update后使用。
- 工程中依赖第三方库版本过低,可以先到repos目录下,使用git clone更新master repo,然后在工程中使用pod update --no-repo-update命令。
上述方案一定程度上加快了CocoaPods的执行速度,但是仍然避免不了要更新全部repo的情况,而实际情况是我们项目当中用到的第三方库大部分只需要十几个,大量的时间被浪费在我们不需要的库上面了。因为CocoaPods是使用中心化的方式来进行管理的,所以当第三方库多起来的时候,就会出现刚才的情况,这个时候可以选择使用Carthage来管理第三方库,它比CocoaPods最大的优势就在于去中心化的方式来管理,不过Carthage的缺点是里面的库还不是很丰富,不过随着时间的推移就不是问题了。
问题三
如果集成到原有项目中报错:'folly/folly-config.h' file not found
则需要更新yarn后重新安装,如果还是无法解决,那就需要回退到稳定版本了。
- 更新 Yarn
warning Your current version of Yarn is out of date. The latest version is "1.6.0" while you're on "0.24.5".
info To upgrade, run the following command:
$ npm upgrade --global yarn
sudo npm upgrade --global yarn
不能更新yarn?
$ yarn --version
yarn install v0.24.5
[1/4] 🔍 Resolving packages...
success Already up-to-date.
✨ Done in 1.01s.
卸了重新安装即可:
npm uninstall -g yarn && npm install -g yarn
问题四
运行.xcworkspace项目后报错:'React/RCTBundleURLProvider.h’ file not found
解决:Delete node modules, then run npm
install (or better yet yarn) and after everything has finished downloading, run react-native
upgrade which should give you the option to replace old files with the template ones, by doing so you re-link your native dependencies in react-native which should fix your problem. Of course don't forget to clean your project in Xcode
翻译:
删除node modules文件夹(一般在根目录)$ sudo rm -r -f node_modules/
,然后运行 $ npm install
(也是在根目录),install 结束后再运行 $ react-native upgrade
代码集成示例
现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把React Native真正集成到应用中了。在我们的2048示例中,首先尝试添加一个显示有"High Score"(得分排行榜)的React Native页面。
- 创建一个
index.ios.js
文件
index.ios.js是React Native应用在iOS上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import导入语句。
# 在项目根目录执行以下命令创建文件:
$ touch index.ios.js
- 添加你自己的React Native代码
为了简单示范,把全部的代码都写到了index.ios.js里(当然实际开发中并不推荐这样做)。
# 进入命令模式
vim index.ios.js
# 在命令模式下按下 'i' 进入输入模式
/*
在输入模式中,可以使用以下按键:
ENTER(回车键) 换行
BACK SPACE / Delete (退格键) 删除光标前一个字符
Fn + BACK SPACE / Delete 删除光标后的一个字符
方向键 在文本中移动光标
HOME/END 移动光标到行首/行尾
Page Up/Page Down 上/下翻页
ESC 退出输入模式,切换到命令模式
*/
/*
在苹果Mac电脑的键盘上没有Home, End, Page UP, Page DOWN这些键,可以通过用Fn键来组合得到同样的功能:
Home = Fn + 左方向
End = Fn + 右方向
Page UP = Fn + 上方向
Page DOWN = Fn + 下方向
向前 Delete = Fn + delete键。
*/
# 在命令模式下按下英文冒号 ':' 就进入了底线命令模式
/*
底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。
在底线命令模式中,基本的命令如下
:w 将编辑的数据写入硬盘档案中
:w! 强制将编辑的数据写入硬盘档案中
:q 离开
:q! 为强制离开不储存档案
:wq 储存后离开
:wq! 强制储存后离开
:set nu 显示行号,设定之后,会在每一行的前缀显示该行的行号
:set nonu 取消行号
按ESC键可随时退出底线命令模式
*/
编辑index.ios.js
如下
//index.ios.js
'use strict';
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class RNHighScores extends React.Component {
render() {
var contents = this.props["scores"].map(
score => <Text key={score.name}>{score.name}:{score.value}{"\n"}</Text>
);
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>
2048 High Scores!
</Text>
<Text style={styles.scores}>
{contents}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
scores: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
// MyReactNativeApp整体js模块的名称
AppRegistry.registerComponent('MyReactNativeApp', () => RNHighScores);
- 原生接入RN模块
现在我们已经在index.ios.js中创建了React Native组件,下一步就是把这个组件添加给一个新的或已有的ViewController。
首先导入RCTRootView的头文件。
#import <React/RCTRootView.h>
原生项目中添加跳转React-Native的按钮并定义点击事件如下
- (IBAction)highScoreButtonPressed:(id)sender {
NSLog(@"High Score Button Pressed");
NSURL *jsCodeLocation = [NSURL
URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL : jsCodeLocation
moduleName : @"MyReactNativeApp"
initialProperties :
@{
@"scores" : @[
@{
@"name" : @"Alex",
@"value": @"42"
},
@{
@"name" : @"Joel",
@"value": @"10"
}
]
}
launchOptions : nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self presentViewController:vc animated:YES completion:nil];
}
- 在
Info.plist
中添加App Transport Security
例外
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
- 启动开发服务器
# 在项目根目录执行:
$ npm start
//或者
$ react-native start
- 运行应用
如果你使用的是Xcode,那么照常编译和运行应用即可。
如果你不想使用Xcode(但是你仍然必须安装Xcode),则可以在命令行中使用以下命令来运行应用:
# 在项目的根目录中执行:
$ react-native run-ios
- 运行结果
Simulator Screen Shot - iPhone X - 2018-04-19 at 15.35.49.png
可以直接编辑index.ios.js,保存后在模拟器上Cmd + R
(真机可以摇一摇)即可看到及时更新
Simulator Screen Shot - iPhone X - 2018-04-19 at 15.44.42.png
Demo下载
RN_AwesomeProject
RN_NumberTileGame
参考:
React Native - English
React Native - 中文
Unable to find a specification for 'boost-for-react-native' depended upon by 'Folly'
解决CocoaPods慢的小技巧
解决CocoaPods各种慢的方案(gem换源+pod repo换源)
Mac终端 vi/vim 的简单使用
网友评论