iOS | 原生App中集成React Native組件指南

前言

本文主要介紹如何將ReactNative集成到原生的iOS項(xiàng)目當(dāng)中, 并在iOS的原生項(xiàng)目當(dāng)中去調(diào)用使用RN組件,把 ReactNative組件集成到iOS應(yīng)用中有如下幾個主要步驟:

  • 配置好 React Native 依賴和項(xiàng)目結(jié)構(gòu)。
  • 了解你要集成的 React Native 組件。
  • 使用 CocoaPods 把這些組件以依賴的形式加入到項(xiàng)目中。
  • 創(chuàng)建 js 文件,編寫 React Native 組件的 js 代碼。
  • 在應(yīng)用中添加一個RCTRootView。這個RCTRootView正是用來承載你的 React Native 組件的容器。
  • 啟動 React Native 的 Packager 服務(wù),運(yùn)行應(yīng)用。
  • 驗(yàn)證這部分組件是否正常工作。

1. 創(chuàng)建iOS原生項(xiàng)目

創(chuàng)建一個名為iOSDemo的iOS原生App項(xiàng)目, 并在項(xiàng)目根目錄下創(chuàng)建一個名為ReactNative的空目錄文件,用于存放和RN相關(guān)的文件, 項(xiàng)目目錄結(jié)構(gòu)如下

image.png

2. 創(chuàng)建React-Native項(xiàng)目

創(chuàng)建一個名為rndemo的RN項(xiàng)目,并保證可以順利的運(yùn)行起來, 如何搭建RN環(huán)境和創(chuàng)建RN項(xiàng)目這里不做過多說明,網(wǎng)上有很多相關(guān)文章, 也可以看我之前的相關(guān)環(huán)境搭建文章, RN項(xiàng)目創(chuàng)建完成后,會自動創(chuàng)建相關(guān)的支持文件以及目錄,代碼結(jié)構(gòu)如下:

image.png

RN運(yùn)行起來效果如下:


image.png

一會我們就會將該頁面集成到iOS的項(xiàng)目當(dāng)中去.并在iOS端調(diào)用打開.

3. 安裝 JavaScript 依賴包

在iOS項(xiàng)目的ReactNative文件夾中創(chuàng)建一個名為package.json的空文本文件

image.png

package.json文件中填入以下內(nèi)容:

{
  "name": "mydemo",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "yarn react-native start"
  },
  "dependencies": {
    "react": "16.9.0",
    "react-native": "0.61.5"
  }
}

注意: reactreact-native版本號需要和RN項(xiàng)目中的版本對應(yīng), 可以參考rndemo中的package.json文件.

version字段沒有太大意義(除非你要把你的項(xiàng)目發(fā)布到 npm 倉庫)。scripts中是用于啟動 packager 服務(wù)的命令。

接下來我們使用 yarnnpm(兩者都是 node 的包管理器)來安裝JavaScript所依賴模塊(其實(shí)就是React和ReactNative框架)。請打開一個終端/命令提示行,進(jìn)入到iOS項(xiàng)目的ReactNative目錄中(即包含有 package.json 文件的目錄),然后運(yùn)行下列命令來安裝:

$ npm install

執(zhí)行完成以后, 所有 JavaScript 依賴模塊都會被安裝到項(xiàng)目根目錄下的node_modules/目錄中(這個目錄我們原則上不復(fù)制、不移動、不修改、不上傳,隨用隨裝)。

node_modules/目錄記錄到.gitignore文件中(即不上傳到版本控制系統(tǒng),只保留在本地)。 node_modules/和iOS的'Pods'文件類似

安裝完成后, 目錄如下:


image.png


4. CocoaPods集成

通過CocoaPods 把 ReactNative 依賴的環(huán)境集成到你當(dāng)前的項(xiàng)目中。

在iOS項(xiàng)目中,創(chuàng)建Podfile文件,如何創(chuàng)建大家都懂, 打開Podfile文件,修改如下:

# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'

target 'iOSDemo' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  pod 'FBLazyVector', :path => "./ReactNative/node_modules/react-native/Libraries/FBLazyVector"
  pod 'FBReactNativeSpec', :path => "./ReactNative/node_modules/react-native/Libraries/FBReactNativeSpec"
  pod 'RCTRequired', :path => "./ReactNative/node_modules/react-native/Libraries/RCTRequired"
  pod 'RCTTypeSafety', :path => "./ReactNative/node_modules/react-native/Libraries/TypeSafety"
  pod 'React', :path => './ReactNative/node_modules/react-native/'
  pod 'React-Core', :path => './ReactNative/node_modules/react-native/'
  pod 'React-CoreModules', :path => './ReactNative/node_modules/react-native/React/CoreModules'
  pod 'React-Core/DevSupport', :path => './ReactNative/node_modules/react-native/'
  pod 'React-RCTActionSheet', :path => './ReactNative/node_modules/react-native/Libraries/ActionSheetIOS'
  pod 'React-RCTAnimation', :path => './ReactNative/node_modules/react-native/Libraries/NativeAnimation'
  pod 'React-RCTBlob', :path => './ReactNative/node_modules/react-native/Libraries/Blob'
  pod 'React-RCTImage', :path => './ReactNative/node_modules/react-native/Libraries/Image'
  pod 'React-RCTLinking', :path => './ReactNative/node_modules/react-native/Libraries/LinkingIOS'
  pod 'React-RCTNetwork', :path => './ReactNative/node_modules/react-native/Libraries/Network'
  pod 'React-RCTSettings', :path => './ReactNative/node_modules/react-native/Libraries/Settings'
  pod 'React-RCTText', :path => './ReactNative/node_modules/react-native/Libraries/Text'
  pod 'React-RCTVibration', :path => './ReactNative/node_modules/react-native/Libraries/Vibration'
  pod 'React-Core/RCTWebSocket', :path => './ReactNative/node_modules/react-native/'

  pod 'React-cxxreact', :path => './ReactNative/node_modules/react-native/ReactCommon/cxxreact'
  pod 'React-jsi', :path => './ReactNative/node_modules/react-native/ReactCommon/jsi'
  pod 'React-jsiexecutor', :path => './ReactNative/node_modules/react-native/ReactCommon/jsiexecutor'
  pod 'React-jsinspector', :path => './ReactNative/node_modules/react-native/ReactCommon/jsinspector'
  pod 'ReactCommon/jscallinvoker', :path => "./ReactNative/node_modules/react-native/ReactCommon"
  pod 'ReactCommon/turbomodule/core', :path => "./ReactNative/node_modules/react-native/ReactCommon"
  pod 'Yoga', :path => './ReactNative/node_modules/react-native/ReactCommon/yoga'

  pod 'DoubleConversion', :podspec => './ReactNative/node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => './ReactNative/node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => './ReactNative/node_modules/react-native/third-party-podspecs/Folly.podspec'

end

注意: path => './ReactNative/node_modules/ 中的路徑需要和自己實(shí)際項(xiàng)目的JS依賴文件目錄對應(yīng)

提示,可以參考rndemo項(xiàng)目中ios部分的Podfile文件, 位置如下, 將里面依賴項(xiàng)拷貝到iOS項(xiàng)目當(dāng)中,但需要修改路徑

image.png

Podfile文件修改完成后, 就可以開始安裝 React Native 的 pod 包了, 在終端執(zhí)行

$ pod install
image.png

看到此界面,表示集成成功.


5. 代碼集成

上述我們已經(jīng)準(zhǔn)備好了所有依賴,可以開始在原生iOS應(yīng)用中把 React Native代碼 真正集成進(jìn)來了, 接下來我們就通過將示例rndemo頁面集成到到iOSDemo中來

React Native 組件

1. 創(chuàng)建一個index.js文件

我們在iOS的ReactNative中創(chuàng)建一個空的index.js文件。(注意在 0.49 版本之前是 index.ios.js 文件)

image.png

index.jsReact Native 應(yīng)用在 iOS 上的入口文件。而且它是不可或缺的!

在新建的index.js中寫入以下代碼:

import {AppRegistry} from 'react-native';
import App from './App';
AppRegistry.registerComponent("rndemo", () => App);

rndemo是整體 js 模塊(即你所有的 js 代碼)的名稱。你在 iOS 原生代碼中添加 React Native 視圖時會用到這個名稱。

2. 添加你自己的 React Native 代碼

將我們需要使用的RN頁面代碼導(dǎo)入到iOS項(xiàng)目中, rndemo項(xiàng)目中的App.js文件復(fù)制到和index.js同目錄下,如下圖

image.png

App.js即是我們在步驟二看到的RN歡迎頁代碼

3.掌握核心科技: RCTRootView

現(xiàn)在我們已經(jīng)在index.js中創(chuàng)建了 React Native 組件,下一步就是把這個組件添加給一個新的或已有的ViewController。

1.創(chuàng)建一個按鈕,用于跳轉(zhuǎn)RN頁面,界面如下

image.png

2. 創(chuàng)建RN視圖:
首先導(dǎo)入RCTRootView的頭文件。

#import <React/RCTRootView.h>

在iOS項(xiàng)目中創(chuàng)建一個按鈕用于跳轉(zhuǎn)RN頁面,代碼如下:

- (IBAction)RNPageButtonDidClick:(UIButton *)sender {
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                moduleName: @"rndemo"
                         initialProperties: nil
                             launchOptions: nil];
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
    [self.navigationController pushViewController:vc animated:YES];
}

6. 測試集成結(jié)果

1. 添加 App Transport Security 例外
Apple 現(xiàn)在默認(rèn)會阻止讀取不安全的 HTTP 鏈接。所以我們需要把本地運(yùn)行的 Packager 服務(wù)添加到Info.plist的例外中,以便能正常訪問 Packager 服務(wù):

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

2. 運(yùn)行 Packager
要運(yùn)行應(yīng)用,首先需要啟動開發(fā)服務(wù)器(即 Packager,它負(fù)責(zé)實(shí)時監(jiān)測 js 文件的變動并實(shí)時打包,輸出給客戶端運(yùn)行)。具體步驟,進(jìn)入iOS項(xiàng)目的index.js所在目錄:終端運(yùn)行:

$ npm start

3. 運(yùn)行應(yīng)用
如果你使用的是 Xcode,那么照常編譯和運(yùn)行應(yīng)用即可。如果你沒有使用 Xcode(但是你仍然必須安裝 Xcode),則可以在命令行中使用以下命令來運(yùn)行應(yīng)用:

$ react-native run-ios

模擬器運(yùn)行后,點(diǎn)擊調(diào)轉(zhuǎn)RN頁面,會調(diào)轉(zhuǎn)到RN歡迎頁:


image.png

4. 報錯問題:
在調(diào)轉(zhuǎn)RN頁面時候可能會遇到以下錯誤

image.png

解決辦法:
在info.plist中,add row添加View controller-based status bar appearance并設(shè)置為NO即可。

總結(jié):

至此,以上就是將RN模塊集成到iOS項(xiàng)目的基本步驟,通過以上步驟,可以了解基本的配置以及集成流程, 在我們實(shí)際使用時候,需要根據(jù)自身項(xiàng)目實(shí)際情況來進(jìn)行引用; 接下來讓我們來看下RN和iOS端是如何進(jìn)行交互的.

參考文檔:

https://reactnative.cn/docs/integration-with-existing-apps/

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

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

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