美文网首页程序员程序员代码改变世界
在iOS项目中集成React-Native并交互

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

作者: 骑着猪的小哥哥 | 来源:发表于2017-07-10 18:04 被阅读313次

    需求

    在公司原有的项目中想使用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,
        },
    });
    

    相关文章

      网友评论

        本文标题:在iOS项目中集成React-Native并交互

        本文链接:https://www.haomeiwen.com/subject/zpquhxtx.html