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

前言

本文主要介绍如何将ReactNative集成到原生的iOS项目当中, 并在iOS的原生项目当中去调用使用RN组件,把 ReactNative组件集成到iOS应用中有如下几个主要步骤:

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

1. 创建iOS原生项目

创建一个名为iOSDemo的iOS原生App项目, 并在项目根目录下创建一个名为ReactNative的空目录文件,用于存放和RN相关的文件, 项目目录结构如下

image.png

2. 创建React-Native项目

创建一个名为rndemo的RN项目,并保证可以顺利的运行起来, 如何搭建RN环境和创建RN项目这里不做过多说明,网上有很多相关文章, 也可以看我之前的相关环境搭建文章, RN项目创建完成后,会自动创建相关的支持文件以及目录,代码结构如下:

image.png

RN运行起来效果如下:


image.png

一会我们就会将该页面集成到iOS的项目当中去.并在iOS端调用打开.

3. 安装 JavaScript 依赖包

在iOS项目的ReactNative文件夹中创建一个名为package.json的空文本文件

image.png

package.json文件中填入以下内容:

{
  "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项目中的版本对应, 可以参考rndemo中的package.json文件.

version字段没有太大意义(除非你要把你的项目发布到 npm 仓库)。scripts中是用于启动 packager 服务的命令。

接下来我们使用 yarnnpm(两者都是 node 的包管理器)来安装JavaScript所依赖模块(其实就是React和ReactNative框架)。请打开一个终端/命令提示行,进入到iOS项目的ReactNative目录中(即包含有 package.json 文件的目录),然后运行下列命令来安装:

$ npm install

执行完成以后, 所有 JavaScript 依赖模块都会被安装到项目根目录下的node_modules/目录中(这个目录我们原则上不复制、不移动、不修改、不上传,随用随装)。

node_modules/目录记录到.gitignore文件中(即不上传到版本控制系统,只保留在本地)。 node_modules/和iOS的'Pods'文件类似

安装完成后, 目录如下:


image.png


4. CocoaPods集成

通过CocoaPods 把 ReactNative 依赖的环境集成到你当前的项目中。

在iOS项目中,创建Podfile文件,如何创建大家都懂, 打开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/ 中的路径需要和自己实际项目的JS依赖文件目录对应

提示,可以参考rndemo项目中ios部分的Podfile文件, 位置如下, 将里面依赖项拷贝到iOS项目当中,但需要修改路径

image.png

Podfile文件修改完成后, 就可以开始安装 React Native 的 pod 包了, 在终端执行

$ pod install
image.png

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


5. 代码集成

上述我们已经准备好了所有依赖,可以开始在原生iOS应用中把 React Native代码 真正集成进来了, 接下来我们就通过将示例rndemo页面集成到到iOSDemo中来

React Native 组件

1. 创建一个index.js文件

我们在iOS的ReactNative中创建一个空的index.js文件。(注意在 0.49 版本之前是 index.ios.js 文件)

image.png

index.jsReact Native 应用在 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页面代码导入到iOS项目中, rndemo项目中的App.js文件复制到和index.js同目录下,如下图

image.png

App.js即是我们在步骤二看到的RN欢迎页代码

3.掌握核心科技: RCTRootView

现在我们已经在index.js中创建了 React Native 组件,下一步就是把这个组件添加给一个新的或已有的ViewController

1.创建一个按钮,用于跳转RN页面,界面如下

image.png

2. 创建RN视图:
首先导入RCTRootView的头文件。

#import <React/RCTRootView.h>

在iOS项目中创建一个按钮用于跳转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. 测试集成结果

1. 添加 App Transport Security 例外
Apple 现在默认会阻止读取不安全的 HTTP 链接。所以我们需要把本地运行的 Packager 服务添加到Info.plist的例外中,以便能正常访问 Packager 服务:

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

2. 运行 Packager
要运行应用,首先需要启动开发服务器(即 Packager,它负责实时监测 js 文件的变动并实时打包,输出给客户端运行)。具体步骤,进入iOS项目的index.js所在目录:终端运行:

$ npm start

3. 运行应用
如果你使用的是 Xcode,那么照常编译和运行应用即可。如果你没有使用 Xcode(但是你仍然必须安装 Xcode),则可以在命令行中使用以下命令来运行应用:

$ react-native run-ios

模拟器运行后,点击调转RN页面,会调转到RN欢迎页:


image.png

4. 报错问题:
在调转RN页面时候可能会遇到以下错误

image.png

解决办法:
在info.plist中,add row添加View controller-based status bar appearance并设置为NO即可。

总结:

至此,以上就是将RN模块集成到iOS项目的基本步骤,通过以上步骤,可以了解基本的配置以及集成流程, 在我们实际使用时候,需要根据自身项目实际情况来进行引用; 接下来让我们来看下RN和iOS端是如何进行交互的.

参考文档:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容