【2017.5.2更新】使用Cocoapods集成的确方便,但在引用一些不支持Cocoapods的第三方RN库时会有依赖问题。而且貌似Cocoapods上的更新也稍显滞后,所以还是推荐使用npm集成,这里推荐另一篇文章iOS现有项目集成React Native。
最近在学习React Native, 相当一部分学习文档在React Native中文网上都有相应的中文翻译,而且比官网更为详尽起来在某些描述下更为详尽。但因为中文网的翻译工作尚未完全结束,部分文档还需从阅读官网的英文原文。现对针对嵌入到现有iOS项目部分Integration With Existing Apps进行一下总结,方便日后查阅。
要嵌入React Native到iOS项目中基本包含以下几步:
- 1.通过npm在工程中下载React及React Native的node模组
- 2.通过CocoaPods下载组件framework
- 3.代码实现
- 4.运行测试
1.通过npm在工程中下载React及React Native的node模组
- 在项目根目录下创建包依赖文件(package dependencies)
package.json
,内容如下
{
"name": "NumberTileGame",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "15.3.2",
"react-native": "0.37.0"
}
}
react和react-native尽量使用最新的版本,旧的版本项目编译时可能报错(官网教程中用到的"react": "15.0.2", "react-native": "0.26.1"我就不能编译通过)。查询当前版本可以使用以下命令:
npm info react
npm info react-native
- 包安装
在package.json
文件所在目录执行命令安装组件,模组最后会装node_modules/
目录下
npm install
2.通过CocoaPods下载组件framework
- 创建
Podfile
文件,在.xcodeproj
文件所在目录下执行
pod init
在Podfile
文件下指定具体安装哪些React Native的依赖库。所指定的每一个库就都称为一个subspect
,具体支持的subspect
可以在node_modules/react-native/React.podspec
中查看。以下是一个事例:
target 'YourProject' do
# Uncomment this line if you're using Swift or would like to use dynamic frameworks
# use_frameworks!
pod 'React', :path => 'node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTNetwork',
'RCTWebSocket', # needed for debugging
# Add any other subspecs you want to use in your project
]
# Pods for YourProject
end
- 开始安装
pod install
3.代码实现
React Native 部分
创建React Native 的页面入口文件index.ios.js
,以官方提供的2048分数页面为例子。
'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,
},
});
// Module name
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
原生部分
在UIViewController
中引入RCTRootView
#import "RCTRootView.h"
创建页面
NSURL *jsUrl = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL : jsUrl
moduleName : @"RNHighScores"
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];
index.ios.js
是官方的默认文件名称,但经过试验,用其他名字也是可以的,只要加载的时候根据具体的名称加载就可以了,感觉可以通过这个特点创建多个模块入口供原生使用。
4.运行测试
App Transport Security
一个小坑,在iOS9之后默认只支持Https协议的网络访问,阅读文档时也看到了,但来回配几次就忘了,导致后续页面总是加载失败。Info.plist
需要配置如下:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
运行Packager
在工程根目录(node_modules所在目录)运行如下语句
npm start
运行App
在Xcode中运行工程或在根目录执行react-native run-ios
命令。
虽然在官方文档中提到可以用
react-native run-ios
命令运行,但在试验过程中一直未能成功,报ENOENT: no such file or directory, uv_chdir
错误,原因未明。
大功告成,以上。