ReactNative 嵌入現(xiàn)有iOS原生應(yīng)用和原生如何跳轉(zhuǎn)到RN不同模塊

如果你打算在新項目中使用當下最熱門的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);

因為只是展示效果,所以頁面都很簡單,下面是展示效果:

最后編輯于
?著作權(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)容

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