如果你打算在新項目中使用當下最熱門的ReactNative混合開發(fā)框架,可以參考ReactNative官網(wǎng)或者ReactNative中文網(wǎng),其中有詳細的教程講解如何初始化一個ReactNative工程。這篇文章講的是如何在已有項目中集成ReactNative(下文簡稱為RN)。
已有項目我們使用一個新建工程NativeAPP來代替。首先,我們使用Xcode創(chuàng)建一個新工程命名為NativeAPP。因為我是通過CocoaPods來添加RN鏈接庫的,相信從事蘋果應(yīng)用開發(fā)的程序猿們都使用過CocoaPods這個簡單方便的第三方庫管理工具吧!這里就不贅述了,不熟悉的可以參照這篇文章CocoaPods的安裝和使用。
安裝React Native
1. 配置package.json安裝依賴包
在NativeAPP的跟目錄下創(chuàng)建一個package.json的配置文件,package.json我們也可以通過react-native init 創(chuàng)建一個新工程拷貝過來。
$ touch package.json
{
"name": "NativeAPP",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
},
"dependencies": {
"react": "15.3.2",
"react-native": "^0.35.0"
}
}
通過npm(Node Package Manager)安裝React 和 React Native 到工程根目錄的node_modules文件夾中:
$ nam install
2. 創(chuàng)建編輯RN入口index.ios.js文件
既然要集成RN,肯定需要加載RN的組件,安裝成功后在NativeAPP的根目錄下創(chuàng)建RN要加載的入口js文件index.ios.js:
$ touch index.ios.js
'use strict'
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class NativeAPP extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('NativeAPP', () => NativeAPP);
原生應(yīng)用
1. 使用Cocoapods添加RN依賴庫
使用終端在NativeAPP工程中創(chuàng)建Podfile:
$ pod init
使用vim打開Podfile編輯,添加RN所需要的鏈接庫:
platform :ios, “8.0”
target 'NativeAPP' do
# 取決于你的工程如何組織,你的node_modules文件夾可能會在別的地方。
# 請將:path后面的內(nèi)容修改為正確的路徑(一定要確保正確~~)。
pod 'React', :path => ‘../node_modules/react-native', :subspecs => [
'Core',
'ART',
'RCTActionSheet',
'RCTAdSupport',
'RCTGeolocation',
'RCTImage',
'RCTNetwork',
'RCTPushNotification',
'RCTSettings',
'RCTText',
'RCTVibration',
'RCTWebSocket',
'RCTLinkingIOS',
]
end
可以根據(jù)需求添加工程中依賴的模塊,例子中是都添加有,多添加是不會出現(xiàn)問題的,但是少添加是一定會出現(xiàn)問題的,會報“Native module cannot be null”的錯誤。
注意需要等到npm install安裝完成后使用 pod install 來安裝鏈接庫,從它的加載路徑我們可以看到是從本地進行加載的,這個時候我們本地如果還沒有完成對應(yīng)的Package的安裝會報錯。所以我們需要安裝完成后再在再執(zhí)行:
$ pod install
2. 配置HTTP請求白名單
在iOS 9以上的系統(tǒng)中,需要配置白名單,否則應(yīng)用無法通過http協(xié)議連接到localhost主機。 如果不這樣做,在嘗試通過http連接到服務(wù)器時,會遭遇這個錯誤 - Could not connect to development server.
打開工程中的 Info.list 文件,添加下面配置即可:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
3. Native代碼跳轉(zhuǎn)RN
打開main.storyboard添加一個導航控制器,設(shè)置它的根視圖控制器為ViewController,在根視圖控制器的View上添加一個Button,并且綁定事件到VC中。

原生跳轉(zhuǎn)到RN本質(zhì)上是通過RCTRootView來加載jsbundle文件的,因此需要在ViewController導入RCTRootView的頭文件和創(chuàng)建RCTRootView對象。
#import "RCTRootView.h"
按鈕點擊事件代碼:
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
RCTRootView *rootView = [[RCTRootView alloc]
initWithBundleURL : jsCodeLocation
moduleName : @"NativeAPP"
initialProperties: nil
launchOptions : nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self.navigationController pushViewController:vc animated:YES];
到這里在iOS原生應(yīng)用中嵌入RN的工作已經(jīng)完成了,接下來就是運行查看效果的時候了,在運行工程之前我們需要先將service服務(wù)運行起來,在項目的根目錄下:
$ npm start
然后再使用Xcode運行我們的原生工程,運行效果圖如下:

原生如何跳轉(zhuǎn)到RN不同模塊
原生嵌入RN一般會遇到有多個跳轉(zhuǎn)RN的地方,而且跳轉(zhuǎn)到不同模塊中去,細心的同學是不是已經(jīng)發(fā)現(xiàn)RCTRootView的:
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
launchOptions:(NSDictionary *)launchOptions;
方法中的字典類型** initialProperties**參數(shù),沒錯我就是通過它來傳遞參數(shù)到j(luò)s的props屬性鏈上,然后在js根據(jù)參數(shù)來進行相應(yīng)模塊加載的(如果有其他更好的方法歡迎留言交流)。
按照同樣的方法在ViewController再添加一個按鈕,按鈕的點擊事件也一樣,區(qū)別是在初期化RCTRootView時:
按鈕一:
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL : jsCodeLocation
moduleName : @"NativeAPP"
initialProperties : @{
@"launchOptions":@{
@"componentName":@"PageOne"
}
}
launchOptions : nil];
按鈕二:
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL : jsCodeLocation
moduleName : @"NativeAPP"
initialProperties : @{
@"launchOptions":@{
@"componentName":@"PageTwo"
}
}
launchOptions : nil];
接下來修改RN入口文件index.ios.js的渲染邏輯:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import CompontNameView from './modules/test'
class PageOne extends Component {
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>這是頁面一!</Text>
</View>
);
}
}
class PageTwo extends Component {
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>這是頁面二!</Text>
</View>
);
}
}
class NativeAPP extends Component {
render() {
var { launchOptions } = this.props;
if (launchOptions && launchOptions.componentName) {
switch (launchOptions.componentName) {
case 'PageOne':
return(
<PageOne/>
);
break;
case 'PageTwo':
return(
<PageTwo/>
);
break;
default:
}
}
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('NativeAPP', () => NativeAPP);
因為只是展示效果,所以頁面都很簡單,下面是展示效果:
