ios developers

React Native集成到现有的原生项目

2018-11-09  本文已影响3853人  安静守护你

因为项目需求,在iOS原生项目中会嵌套几个RN界面,这就牵涉到了原生代码中嵌套RN代码的问题,至于集成步骤以及过程中遇到的坑都在下面一一列举,以帮助后来人。

前提

RN环境已经搭建完成,如若未完成,请移步
React Native环境搭建

将React Native集成到iOS应用中主要有如下几个步骤:

  1. 配置好React Native依赖和项目结构
  2. 了解你要集成的React Native组件
  3. 使用CocoaPods把这些组件以依赖的形式加入到项目中
  4. 创建js文件,编写React Native组件的js代码
  5. 在应用中添加一个RCTRootView,这个RCTRootView正是用来承载你的React Native组件的容器
  6. 启动React Native的Packager服务,运行应用
  7. 验证这部分组件是否正常工作

1. 配置项目目录结构

我在此也是为了更加深入的了解RN,所以在这里拿以前的小demo来做示范了。
首先创建一个空目录用于存放React Native项目,然后在这个空目录中创建一个ios子目录,把现有的iOS项目拷贝到ios子目录中

目录结构

2. 安装JavaScript依赖包

在项目根目录下创建一个名为package.json的文件,其中填入以下内容:

{
  "name": "MyReactNativeApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  }
}

接下来使用yarn或者npm(两者都是node的包管理器)来安装React和React Native模块。
打开终端,进入到根目录中(即package.json)文件所在目录,然后运行以下命令安装:

yarn add react-native

这样默认安装最新版本的React Native,命令执行完毕后可以看到输出中有两个警告信息:

warning " > react-native@0.57.4" has unmet peer dependency "react@16.6.0-alpha.8af6728".
warning Your current version of Yarn is out of date. The latest version is "1.12.3", while you're on "1.9.4".

第一个警告提示还要安装指定版本的React,第二个警告说是yarn版本不是最新的
然后执行命令安装指定版本的React

yarn add react@16.6.0-alpha.8af6728

注意:必须严格匹配警告信息中所列出的版本,高了或者低了都是不可以嘀!

完成这个步骤之后可以发现我们的根目录下多了一些东西:

根目录

项目根目录下的node_modules目录中安装的都是JavaScript的以来模块(对于这个目录,我们的原则是不复制、不移动、不修改、不上传、随用随装)

node_modules/目录记录到.gitignore文件中(即不上传到版本控制系统,只保留到本地)

3. 安装CocoaPods

CocoaPods是针对iOS和Mac开发的包管理工具。执行一下命令安装CocoaPods

brew install cocoapods

安装就不用过多的说了(毕竟都安装的有)

4. 配置CocoaPods依赖

React Native框架整体是作为node模块安装到项目中的。接下来我们就要在CocoaPods的Podfile中指定我们需要使用的subspecs

可用的subspecs都列在node_modules/react-native/React.podspec文件中,基本上都是按照其功能命名的。一般来说第一个要添加的就是Core,其包含了必须的AppRegistryStyleSheetView以及其他的一些React Native核心库。如果要使用React Native的Text库(即<Text>组件),那就需要添加TCTTextsubspec,等等。

我们需要在Podfile文件中指定所需要的subspec。创建Podfile的最简单方法就是在/ios目录中使用CocoaPods的init命令(如果原先项目中已经创建了Podfile文件,可以跳过此步):

pod init

这样Podfile就已经创建了,接下来就需要调整其内容以满足集成需求,调整后的Podfile内容类似下面的:

# target的名字一般与你的项目名字相同
target 'NumberTileGame' do

  # 'node_modules'目录一般位于根目录中
  # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
  pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    'CxxBridge', # 如果RN版本 >= 0.47则加入此行
    'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket', # 调试功能需要此模块
    'RCTAnimation', # FlatList和原生动画功能需要此模块
    # 在这里继续添加你所需要的其他RN模块
  ]
  # 如果你的RN版本 >= 0.42.0,则加入下面这行
  pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'

  # 如果RN版本 >= 0.45则加入下面三个第三方编译依赖
  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

end

修改好Podfile文件后,就可以开始安装React Native的pod包了:

pod install

5. RN代码集成

依赖搞好之后,就可以愉快的搞代码咯,接下来我们在根目录中创建一个名为home.js的文件(个人建议功能文件单独创建文件夹放到一块,不要都挤在根目录中),实现以下内容(这里的内容可以随便咯):

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, NativeModules, NativeAppEventEmitter} from 'react-native';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
  android:
    'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

var rn = NativeModules.HmRNViewController;

type Props = {};

export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>Hello World</Text>
        <Text style={styles.instructions}>这里是RN界面</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,
  },
});

代码码好了,接下来就是要iOS原生应用能够调用的到的这个页面,我们需要在项目根目录下创建一个空的index.js文件(入口文件建议放在根目录下)

index.js文件是React Native应用在iOS上的入口文件,该入口文件也可以像iOS的main入口文件一样简单,在其中实现以下内容即可完成:

import {AppRegistry} from 'react-native';
import home from './home.js';  // 引入当前目录下的home.js文件

// 注册组件
AppRegistry.registerComponent('homePage', () => home);

6. iOS代码集成

RN代码搞定,接下来就是在iOS原生项目中对接RN了,这也是重点:

假设当前的原生项目中A界面有一个按钮,点击之后要让跳转到RN界面,主要实现如下:
在iOS项目中新建一个ViewController界面B,在B界面的viewDidLoad方法中实现以下代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.title = @"B";
    NSURL *jsCodeLocation;
    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"homePage" initialProperties:@{@"name" : @"Max", @"value" : @"123456"} launchOptions:nil];
    // 这里如果引入的是一个页面,可以使用self.view = rootView;,也可以使用[self.view addSubview:rootView];,不过使用addSubview:方法必须要给rootView设置frame
    //如果是一个组件(如按钮、轮播图等等),则可以直接使用[self.view addSubview:rootView];将组件添加到当前view,并设置frame值:rootView.frame = CGRectMake(0, 100, 100, 100);
    self.view = rootView;
}

A界面的按钮点击事件中实现的功能就是普通的跳转到B界面,这里就略去了

7. 运行项目

运行项目,点击A界面的按钮,即可跳转到RN界面:

报错咯

别慌别慌,要稳住,不就是一个红屏嘛 哈哈哈
出现这个红屏报错的原因在于:有没有发现运行项目少了点什么?一般情况下,RN项目运行的时候都会自动启动packager服务的,但是这里没有自动启动,至于怎么设置自动启动packager服务我暂时也不知道,但是可以手动启动的:

打开终端,到达项目根目录下(即package.json所在目录),然后执行命令:

npm start

然后终端形如:

启动packager服务

刚刚打开的终端就用于启动packager服务了,想要运行项目要么再打开一个终端至根目录下运行react-native run-ios,要么进入ios文件夹打开Xcode运行,运行结果如下:

运行结果

在RN界面如果不想要原生的导航栏,可以在B界面中隐藏导航栏,总之,随便搞起来吧

这篇文章所介绍的主要是更改目录结构,环境配置等等,具体代码部分很有限,所以源代码就不贴出来了。在后面还会陆续的贴出来我在学习RN中遇到的问题我和经验分享。

上一篇下一篇

猜你喜欢

热点阅读