原生 iOS 項目集成 React Native

創(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)載請注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 想了很久,要先介紹各種組件的實際應(yīng)用好,還是先介紹怎么把React Native集成到原生項目好。因為想起,一旦開...
    朱_源浩閱讀 23,065評論 84 129
  • 核心概念 如果你正準備從頭開始制作一個新的應(yīng)用,那么React Native會是個非常好的選擇。但如果你只想給現(xiàn)有...
    made_China閱讀 1,522評論 1 2
  • 小時候 你是過節(jié)的味道 我想啊想 盼啊盼 你的味道總讓我饞 長大后 你是家鄉(xiāng)的味道 我走啊走 望啊望 你的味道總讓...
    春暖花開啦閱讀 263評論 0 2
  • 口欲期,一歲以前,快感中心集中在口腔部位,這一階段需要發(fā)展出基本的信任,也就是一個人由衷地相信,外部世界是愿意滿足...
    尹二尹閱讀 1,009評論 0 0

友情鏈接更多精彩內(nèi)容