創(chuàng)建一個 React Native 項目并寫一個純的 React Native 應(yīng)用可以參考官方指南。
Android 項目集成 React Native 可以參考 原生 Android 項目集成 React Native。
本文主要介紹原生 iOS 項目集成 React Native 并用于部分頁面開發(fā)的流程。開發(fā)環(huán)境為 macOS 10.12、Xcode 8.0、React Native 0.35.0。而官方給出的 植入原生 iOS 應(yīng)用指南 只對應(yīng)到 0.28 版本。最新版(當前為 0.35)的集成方案稍微有些變動。
0. 安裝 CocoaPods
iOS 開發(fā)者可以跳過這一步。
0.0 使用 rvm 安裝/更新 ruby 環(huán)境
安裝 cocoapods 對 ruby 版本有要求
$ curl -L https://get.rvm.io | bash -s stable
$ source ~/.rvm/scripts/rvm
// 查看遠程 ruby 版本
$ rvm list known
// 查看本地 ruby 版本
$ rvm list
$ rvm install 2.3.0
0.1 使用 gem 安裝 cocoapods
如要修改 gem 的鏡像地址
$ gem sources -l
// 刪除已有的源地址
$ gem sources -r https://rubygems.org/
// 添加需要的源地址
$ gem sources -a https://ruby.taobao.org/
$ gem sources -l
安裝 cocoapods
$ gem install cocospods
$ cd ~/.cocoapods/repos/
$ git clone https://github.com/CocoaPods/Specs.git master
順利的話安裝 ruby 和 cocoapods 兩步都會成功,如果失敗了可以針對具體問題去網(wǎng)上搜索相關(guān)教程或解決方案。這里不詳述。
1. 創(chuàng)建/修改 iOS 項目
集成 React Native 要求 iOS 系統(tǒng)版本不小于 7.0。
2. 添加 package.json
在 iOS 項目根目錄新建文件 package.json,內(nèi)容如下(參考 react-native init 生成的 package.json 文件)
{
"name": "react-native-sample",
"version": "0.0.1",
"description": "sample of react native embedding ios",
"main": "index.ios.js",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"author": "danke77",
"license": "ISC",
"dependencies": {
"react": "^15.3.2",
"react-native": "^0.35.0"
},
"devDependencies": {
}
}
執(zhí)行 npm install 就可以安裝 dependencies 下的 npm 組件了。
這個時候在 iOS 項目根目錄就生成了 node_modules/ 文件夾,里面就是一些用到的組件。
在 .gitignore 中添加
# node.js
node_modules/
npm-debug.log
執(zhí)行 react-native upgrade 可以更新已有組件。
3. 添加 index.ios.js
在 iOS 項目根目錄創(chuàng)建目錄 js/,js 相關(guān)的代碼就放在這個文件夾下。
在 js/ 下添加 App.js,內(nèi)容如下
import React, { Component } from 'react'
import { View, Text, StyleSheet } from 'react-native'
export default class extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.text}>
Hello React Native!
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ffffff'
},
text: {
fontSize: 20,
color: '#333333'
}
})
在 iOS 項目根目錄新建文件 index.ios.js,內(nèi)容如下
import { AppRegistry } from 'react-native'
import App from './js/App'
AppRegistry.registerComponent('navigation', () => App)
這里的 navigation 一般會根據(jù)模塊功能命名,后面還會用到。
當然也可以把 App.js 的內(nèi)容寫在 index.ios.js 里,但這樣寫更清晰一些,尤其是項目大了文件多的情況。
4. 用 cocoapods 集成 React Native
在 iOS 項目根目錄的 Podfile 文件(沒有則創(chuàng)建)添加 React Native 相關(guān)內(nèi)容
target 'HelloReactNative' do
platform :ios, '7.0'
source 'https://github.com/CocoaPods/Specs.git'
# 這里的 :path 內(nèi)容取決于 node_modules/ 實際所在的位置
pod 'React', :path => ‘./node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTImage',
'RCTNetwork',
'RCTWebSocket', # needed for debugging
# Add any other subspecs you want to use in your project
]
要在這里添加項目需要的依賴,如要使用 React Native 的 Text 則必須要添加 RCTText 依賴(pod 'React/RCTText')。
然后在根目錄執(zhí)行 pod install。
5. React Native 相關(guān)的 ViewController
創(chuàng)建一個用于容納 React Native 組件的 ViewController,并添加 RCTRootView,它會把 React Native 組件解析成原生的 UIView。
#import "HelloReactViewController.h"
#import <RCTRootView.h>
@interface HelloReactViewController ()
@end
@implementation HelloReactViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
#ifdef DEBUG
NSURL * jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
NSURL * jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/index.ios" withExtension:@"bundle"];
#endif
RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"navigation"
initialProperties:nil
launchOptions:nil];
self.view = rootView;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
jsCodeLocation 是 React Native 資源加載的路徑,可以通過網(wǎng)絡(luò)加載本地的資源文件(主要用于本地調(diào)試),或者將其打包成 js bundle 文件(用于發(fā)布正式包)。
moduleName 對應(yīng) React Native 組件的入口,必須和前面的 AppRegistry.registerComponent('navigation', () => App) 里的 navigation 對應(yīng)。
6. 啟動服務(wù)
debug 模式下需要啟動 package server,在 package.json 所在目錄(一般為項目根目錄)下執(zhí)行 npm start,它等效于 package.json 內(nèi) scripts 下的 node node_modules/react-native/local-cli/cli.js start,相當于啟動一個本地服務(wù)。
Terminal 顯示如下表示服務(wù)已正常啟動
> react-native-module@0.0.1 start /Users/danke77/Projects/react-native/HelloReactNative
> node node_modules/react-native/local-cli/cli.js start
Scanning 581 folders for symlinks in /Users/danke77/Projects/react-native/HelloReactNative/node_modules (17ms)
┌────────────────────────────────────────────────────────────────────────────┐
│ Running packager on port 8081. │
│ │
│ Keep this packager running while developing on any JS projects. Feel │
│ free to close this tab and run your own packager instance if you │
│ prefer. │
│ │
│ https://github.com/facebook/react-native │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Looking for JS files in
/Users/danke77/Projects/react-native/HelloReactNative
[2016-10-17 17:06:48] <START> Building Dependency Graph
[2016-10-17 17:06:48] <START> Crawling File System
[Hot Module Replacement] Server listening on /hot
React packager ready.
[2016-10-17 17:06:49] <END> Crawling File System (966ms)
[2016-10-17 17:06:49] <START> Building in-memory fs for JavaScript
[2016-10-17 17:06:49] <END> Building in-memory fs for JavaScript (260ms)
[2016-10-17 17:06:49] <START> Building in-memory fs for Assets
[2016-10-17 17:06:50] <END> Building in-memory fs for Assets (138ms)
[2016-10-17 17:06:50] <START> Building Haste Map
[2016-10-17 17:06:50] <START> Building (deprecated) Asset Map
[2016-10-17 17:06:50] <END> Building (deprecated) Asset Map (104ms)
[2016-10-17 17:06:50] <END> Building Haste Map (428ms)
[2016-10-17 17:06:50] <END> Building Dependency Graph (1825ms)
7. 開發(fā)調(diào)試
模擬器上可以通過工具欄的 Hardware->Shake Gesture 或快捷鍵調(diào)出開發(fā)調(diào)試菜單;真機上可以通過搖一搖調(diào)出。
8. 發(fā)布正式包
React Native 的開發(fā)版需要有一個 package server 隨時發(fā)送更新后的 js bundle 文件。如果要打正式包,需要把 js bundle 文件保存到 iOS 項目的目錄下。這樣,正式包就不需要 server 支持了,可獨立運行。
在根目錄下創(chuàng)建 bundle/ 文件夾,執(zhí)行以下命令將 js bundle 保存到資源目錄下
$ react-native bundle --platform ios --dev false --entry-file index.ios.js --bundle-output ./bundle/index.ios.bundle --assets-dest ./bundle
在 bundle/ 下就會生成 index.ios.bundle 文件及 assets/ 文件夾,后者會放 React Native 中用到的資源如圖片等。
然后將生成的 bundle/ 文件夾以 Create folder references 的形式導(dǎo)入到工程里,就可以打正式包了。
本文是 慌不要慌 原創(chuàng),發(fā)表于 https://danke77.github.io/,請閱讀原文支持原創(chuàng) https://danke77.github.io/2016/10/19/react-native-embedding-ios/,版權(quán)歸作者所有,轉(zhuǎn)載請注明出處。