在iOS项目中集成React-Native并交互

需求

在公司原有的项目中想使用RN,但罗马不是一天建成的,没办法把所有代码全部换成RN,而且原来的项目功能比较多,我不认为全部换成RN就是好的,所以准备将项目中的一些合适用于RN的页面先转变过来,这篇文章就是在iOS项目中集成RN的步骤。和一些简单的交互。
效果图


Demo.gif
我写了一个简单的项目更新到了github上,希望和大家更好的交流https://github.com/gjjggg/iOSRN.git

前提

1电脑已经安装过react-native相关环境
2电脑已经安装过Cocoapods(官方推荐的办法,如果想在项目中使用Cocoapods可以找一下唐巧写的安装教程)

步骤

  1. 创建:首先我们先创建一个iOS项目,我命名为iOS-RN;
  2. package.json:我们把具体的依赖包记录在package.json文件中。如果项目根目录中没有这个文件,那就自己创建一个。用于初始化react-native。 (对于一个典型的React Native项目来说,一般package.json和index.ios.js等文件会放在项目的根目录下。而iOS相关的原生代码会放在一个名为ios/的子目录中,这里也同时放着你的Xcode项目文件(.xcodeproj)。(放置位置如图))
屏幕快照 2017-07-10 下午1.54.11.png

package.json内容如图

屏幕快照 2017-07-10 下午2.08.05.png
{
//name对应着项目得名字
  "name": "iOS-RN",
  //version字段没有太大的意义
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    //react 版本号
    "react": "16.0.0-alpha.6",
    //react-native  版本号 (react和react-native要对应 这里我建议用相对稳定的版本 这里我用的0.44.3)
    "react-native": "0.44.3"
  }
}

package.json配置好咱们就安装依赖包
使用终端安装 $ npm install一下( 在包含有package.json文件的目录(一般也就是项目根目录)中运行下列命令来安装)

Last login: Mon Jul 10 14:16:51 on ttys001
guohongandeiMac-2:~ guohongan$ cd /Users/guohongan/Desktop/iOS-RN 
guohongandeiMac-2:iOS-RN guohongan$ npm install

如果报错看一下package.json里的name是不是和项目名对应,react和react-native版本是否对应

3.React Native框架:React Native框架整体是作为node模块安装到项目中的。下一步我们需要在CocoaPods的Podfile中指定我们所需要使用的组件。
首先我们在项目的根目录 $ pod init (创建Podfile)

屏幕快照 2017-07-10 下午2.44.29.png

根目录就会多一个Podfile

屏幕快照 2017-07-10 下午2.45.16.png

下一步$ vim Podfile (打开Podfile文件) 点 ‘e’ 进入编辑e
我们在里面写这几句话 点 ‘esc’ 然后输入‘:’'w''q'保存退出编辑

屏幕快照 2017-07-10 下午2.48.54.png
// 9.0 最低兼容到多少
platform :ios, ‘9.0’ 
//iOS-RN 项目得名字
target 'iOS-RN' do 
 // 'node_modules'目录一般位于根目录中
 // 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
 // './node_modules/react-native' 这个路径是根据Podfile的位置
pod 'React', :path => './node_modules/react-native', :subspecs => [
    'Core',
    'DevSupport', //如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket'
      // 在这里继续添加你所需要的模块
  ]
   // 如果你的RN版本 >= 0.42.0,请加入下面这行
   // './node_modules/react-native/ReactCommon/yoga' 这个路径是根据  Podfile的位置
pod "Yoga", :path => "./node_modules/react-native/ReactCommon/yoga"

end

创建好了Podfile后,就可以开始安装React Native的pod包了。$ pod install
install 成功以后的根目录如图所示

屏幕快照 2017-07-10 下午3.00.03.png

现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把React Native真正植入到应用中了
—————————————————————————————————————————————————————

接下来我们来在iOS中创建原生界面

创建一个index.ios.js文件:首先创建一个空的index.ios.js文件。一般来说我们把它放置在项目根目录下。(index.ios.js是React Native应用在iOS上的入口文件。而且它是不可或缺的)(为了简单示范,把全部的代码都写到了index.ios.js里 实际开发中不推荐)

# 在项目根目录执行以下命令创建文件:
$ touch index.ios.js

然后用WebStorm来打开整个项目
在index.ios.js里

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View
} from 'react-native';

export default class iOSRN 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.android.js
                </Text>
                <Text style={styles.instructions}>
                    Double tap R on your keyboard to reload,{'\n'}
                    Shake or press menu button 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('iOSRN', () => iOSRN);

在iOS项目创建一个集成于 UIView 的类来展示RN界面 我这里叫ReactView
ReactView.m

#import "ReactView.h"
#import <RCTRootView.h>
@implementation ReactView
-(instancetype)initWithFrame:(CGRect)frame{
    self =[super initWithFrame:frame];
    if (self) {
        NSString * strUrl = @"http://localhost:8081/index.ios.bundle?platform=ios&dev=true";
        NSURL * jsCodeLocation = [NSURL URLWithString:strUrl];
        // 这里的moduleName一定要和下面的index.ios.js里面的注册一样
        RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation  moduleName:@"IOSRN"
                                                      initialProperties:nil
                                                          launchOptions:nil];
        
        [self addSubview:rootView];
        
        rootView.frame = self.bounds;
    }
    return self;

}

最后我们把View贴到ViewController上面

ReactView * reactView = [[ReactView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:reactView];

在iOS项目中Info.plist文件下添加

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

最后把RN的服务器打开( 一定等服务器运行起来 在运行项目)

 # 找到根目录
    $ react-native start

运行项目 这些就是从原生iOS项目跳转RN 下面再说下从RN跳回原生iOS项目👇
————————————————————————————————————————————
之前是写的比较简单所以没有多建页面 下面因为要跳转 所以页面比较多如果看不懂的可以看下git上的demo
从RN跳回原生iOS项目:https://github.com/gjjggg/iOSRN.git
1.新建 RCTModules 类,继承 NSObject 封装一个方法使用“通知”进行消息的传送从而实现页面的跳转
RCTModules类
RCTModules.h

#import <Foundation/Foundation.h>
// 导入RCTBridgeModule类,这个是react-native提供
#import "RCTBridgeModule.h"
// 遵守RCTBridgeModul协议
@interface RCTModules : NSObject<RCTBridgeModule>

@end

RCTModules.m

#import "RCTModules.h"
#import "RCTBridge.h"
@implementation RCTModules
RCT_EXPORT_MODULE(RTModule)
//RN跳转原生界面
RCT_EXPORT_METHOD(RNOpenOneVC:(NSString *)msg){
    
    NSLog(@"RN传入原生界面的数据为:%@",msg);
    //主要这里必须使用主线程发送,不然有可能失效
    dispatch_async(dispatch_get_main_queue(), ^{
       
    [[NSNotificationCenter defaultCenter]postNotificationName:@"RNOpenOneVC" object:nil];
    });
}
@end

2.接下来在TwoViewController.m中添加通知的方法
TwoViewController.m

#import "TwoViewController.h"
#import "ReactView.h"
//要跳转的原生界面
#import "ThreeViewController.h"
@interface TwoViewController ()

@end

@implementation TwoViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.navigationController.navigationBarHidden = YES;
    
   
    
    //self.navigationItem.title = @"我是包含RN的原生页面哟~";
    ReactView * reactView = [[ReactView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width,  self.view.frame.size.height)];
    [self.view addSubview:reactView];
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doPushNotification:) name:@"RNOpenOneVC" object:nil];
}

- (void)doPushNotification:(NSNotification *)notification{
    NSLog(@"成功收到===>通知");
    ThreeViewController *one = [[ThreeViewController alloc]init];

    
    [self.navigationController pushViewController:one animated:YES];
    
    //注意不能在这里移除通知否则pus进去后有pop失效
}

3.创建ThreeViewController继承于UIViewController
4.最后RN中的界面 我是自己建了一个Two界面代码如下

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
//需要导入NativeModules组件,这个是官方提供给我们与原生交互的组件,通过它我们才能调用到原生的方法
    NativeModules
} from 'react-native';
// 看到 RTModule 是不是很熟悉,没错这个就是原生中写的那个类
// 后面一定要一样哦
var RNModules  = NativeModules.RTModule;
export default class Home extends Component {
    render() {
        return (
            <View style={styles.container}>
              // RNOpenOneVC这个也是写在原生里面的再RNModules中哦~
                <Text style={styles.instructions} onPress={()=>RNModules.RNOpenOneVC('测试')} >
                我还是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,
    },
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,832评论 25 707
  • React Native学习<一> 认识Recat Native 博客原文:http://www.jianshu....
    AFinalStone阅读 2,661评论 0 12
  • 想了很久,要先介绍各种组件的实际应用好,还是先介绍怎么把React Native集成到原生项目好。因为想起,一旦开...
    朱_源浩阅读 22,745评论 84 129
  • 今天(2016.11.3晚),在简书上创建了自己的新文集和新专题——音为有你。不是一时的冲动,而是从接触简书第二天...
    春耕秋实阅读 180评论 0 0
  • 迷迷糊糊地睁开眼,刺鼻的消毒水味弥漫在空气中。周围一片安静,我以为自己进了太平间,吓得后背冒出了冷汗。 低着缠着纱...
    王晓白阅读 267评论 0 0