美文网首页React NativeReact NativeiOS基础扩展
7) React Native 集成到原生项目(iOS)

7) React Native 集成到原生项目(iOS)

作者: 朱_源浩 | 来源:发表于2016-08-13 18:12 被阅读17971次

    想了很久,要先介绍各种组件的实际应用好,还是先介绍怎么把React Native集成到原生项目好。
    因为想起,一旦开始写各种组件的应用,就会花很长很长的篇幅,会把这个挺重要的内容抛到好远,而集成到原生项目又是很多人所需要学习的(像我一样哈,直接替代现有的项目是不科学的,作为一个模块集合进去才比较现实),所以决定了,还是先花两个篇章写写怎么将React Native集成到原生项目以及JS与原生之间简单的交互。


    由于React并没有假设你其余部分的技术栈——它通常只作为MVC模型中的V存在——它也很容易嵌入到一个并非由React Native开发的应用当中。实际上,它可以和常见的许多工具结合,譬如CocoaPods。

    一、准备工作

    1. React Native 开发基础环境

    这个可以直接参考我写的第二篇文章React Native 环境搭建和创建项目(Mac)。如果已经按上篇文章操作过,或者说已经在Mac平台已经成功运行过React Native应用,那肯定是已经有了开发基础环境,可以直接忽略这一步。

    1) 安装Node.js
    方式一:
    安装 nvm(安装向导在这里)。然后运行命令行如下:

    nvm install node && nvm alias default node
    

    这将会默认安装最新版本的Node.js并且设置好命令行的环境变量,这样你可以输入node命令来启动Node.js环境。nvm使你可以可以同时安装多个版本的Node.js,并且在这些版本之间轻松切换。
    方式二:
    先安装Homebrew,再利用Homebrew安装Node.js,运行命令行如下:

    //安装Home-brew
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    //安装Node.js
    brew install node
    

    2) 安装React Native的命令行工具(react-native-cli)

    npm install -g react-native-cli
    

    2. 安装CocoaPods

    本文只写使用CocoaPods安装React Native的方式,比较支持使用,也比较简单直接。
    若依旧不想使用CocoaPods,想直接集成的朋友可以参考下面两篇文章:
    1)【iOS&Android】RN学习3——集成进现有原生项目

    1. reactnative集成到原生ios项目 文中的手动集成react-native

    如果之前已经安装并使用过CocoaPods,请忽略这一步(相信只要是iOS开发,一定大多数都接触过了哈)。
    若没有安装,则运行命令如下:

    gem install  cocoa pods
    //权限不够则运行下面一句
    sudo gem install cocoapods
    

    二、集成React Native

    1. 安装React Native

    1)创建ReactComponent文件夹和配置文件

    在项目中建一个名为ReactComponent的文件夹, 用于存放我们react-native的相关文件, 再创建一个package.json文件, 用于初始化react-native.(文件夹名字自定义哈)
    文件目录结构如下:


    文件目录结构1.png

    创建package.json文件,文件内容如下:

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

    其中,name为项目名称。dependencies里为react和react-native的版本信息。
    建议利用react-native init AwesomeProject新建新项目时会自动创建package.json,直接把文件复制过来,更改name为自己的原生项目名,以确保react、和react-native的版本最新哈。

    2)安装React Native依赖包

    在ReactComponent目录下运行命令行:

    npm install
    

    运行效果如下:

    npm install.png

    这里很需要耐心,曾经的我看着毫无反应的控制台就放弃了n次。
    可能静下心去看部动漫回来就会发现它只想成功了。
    实在install不回来的话,如果之前有创建过React Native项目,把里面的node_modules直接拷贝过来,也是没有问题(个人尝试过)。

    2. 创建 index.ios.js(js文件入口)

    在ReactComponent文件夹里创建index.ios.js文件,作为js文件入口。


    目录结构2.png

    index.ios.js文件内容如下:

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View
    } from 'react-native';
    
    class NativeRNApp 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('NativeRNApp', () => NativeRNApp);
    
    

    3. Cocoapods集成React Native

    若原项目无使用Cocoapods,则在根目录下创建Podfile。(有则直接添加pod相关代码)
    目录结构如下:


    目录结构3.png

    Podfile文件内容为(需确保路径对):

    platform :ios, “7.0”
    
    # 取决于你的工程如何组织,你的node_modules文件夹可能会在别的地方。
    # 请将:path后面的内容修改为正确的路径(一定要确保正确~~)。
    pod 'React', :path => ‘./ReactComponent/node_modules/react-native', :subspecs => [
     'Core',
      'ART',
      'RCTActionSheet',
      'RCTAdSupport',
      'RCTGeolocation',
      'RCTImage',
      'RCTNetwork',
      'RCTPushNotification',
      'RCTSettings',
      'RCTText',
      'RCTVibration',
      'RCTWebSocket',
      'RCTLinkingIOS',
    ]
    #需要的模块依赖进来便可,这里是为了举例子,列举所有的模块
    

    然后在根目录执行pod更新命令:

    pod install
    
    /*
    以下是失败情况的处理
    */
    //  pod命令过慢则可尝试下面命令
    pod install --verbose --no-repo-update
    
    //  其中无法正常下载pod install的解决方法:
    (or更新最新的CocoaPods version: 0.39.0  查看方法 pod --version)
    gem sources --remove https://rubygems.org/
    gem sources -a 
    gem sources -l 
    
    # 注意 taobao 是 https; 
    # gem如果版本太老可以更新:sudo gem update --system; 
    # 更新pod repo:pod repo update
    
    

    运行效果:


    pod install.png

    三、原生项目处理

    1. 向对应ViewController 添加RCTRootView

    下面的ReactViewController是我创建的专门放React Native模块的ViewController,有必要的话也可对RCTRootView进行进一步封装(就不用每次都重新配置一次)。
    ReactViewController代码如下:

    #import "ReactViewController.h"
    #import <RCTRootView.h>
    
    @interface ReactViewController ()
    
    @end
    
    @implementation ReactViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        NSString * strUrl = @"http://localhost:8081/index.ios.bundle?platform=ios&dev=true";
        NSURL * jsCodeLocation = [NSURL URLWithString:strUrl];
        
        RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                             moduleName:@"NativeRNApp"
                                                      initialProperties:nil
                                                          launchOptions:nil];
        self.view = rootView;
        //  也可addSubview,自定义大小位置
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    项目结构如下:


    项目结构.png

    2. iOS项目更新App Transport Security

    在iOS 9以上的系统中,除非明确指明,否则应用无法通过http协议连接到localhost主机。 我们建议你在Info.plist文件中将localhost列为App Transport Security的例外。 如果不这样做,在尝试通过http连接到服务器时,会遭遇这个错误 - 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>
    

    配置效果如下:


    App Transport Security配置.png

    3. 启动开发服务器

    在运行我们的项目之前,我们需要先启动我们的开发服务器。进入 reactnative目录 ,然后命令行启动服务:

    react-native start
    

    4. 运行iOS项目

    运行成功效果如下:


    运行效果.png

    可以成功看到上面的界面,那就恭喜集成成功了。之前弄这个弄了一两天,主要卡在npm install不回来那一步,然后pod是不可能的。。写个更加详细的教程希望大家能更轻松的把React Native集成到原生项目中哈,有问题欢迎留言哈。

    目前暂时把demo打包到自己的百度云(以后再想办法放到github):
    https://pan.baidu.com/s/1hrKnlvm


    因为没继续这方面的工作所以好久没更新了,可能代码因为rn的更新会有些问题,最好更新下pod的版本,看看官方文档,看到评论里有相应的讨论,出现问题的朋友最好也看看评论哈哈,可能有解决绑法♪───O(≧∇≦)O────♪

    已有的成果如下:
    1) React Native 简介与入门
    2) React Native 环境搭建和创建项目(Mac)
    3) React Native 开发之IDE
    4) React Native 入门项目与解析
    5) React Native 相关JS和React基础
    6) React Native 组件生命周期(ES6)
    7) React Native 集成到原生项目(iOS)
    8) React Native 与原生之间的通信(iOS)
    9) React Native 封装原生UI组件(iOS)

    相关文章

      网友评论

      • 山姆极客:大神有没有尝试过用swift来写通信这块
        @lz
        朱_源浩:木有,,,原理应该类似诶
      • a54866e3da50:博主写得好详细,每一步都很清晰,文图丰富,让人当成手册来操作都没问题,赞一个!
        朱_源浩:谢谢:blush:
      • 26b0e5262789:这样试了一下,两个页面来回 push 和back 时,内存会一直增加降不下来,怎么回事?知道如何解决吗?
        26b0e5262789:@南湖滨 RN 0.48版本没这个问题
        阿咿呀嘿:我也遇到这个问题,请问知道原因和解决方法了吗
      • 追风筝的荧火虫:最后运行时模拟器红屏显示:
        syntax Error: unexpected identifier ‘React’.
        import call expects exactly one argument.
        { “line”:1395,
        “sourceURL”: “http://localhost:8081/AppEntrance.bundle?platform=ios&dev=true
        }

        有人遇到这样的问题吗?
      • xclidongbo:小伙儿挺不错,看了你的博客. 不过评论挂了.
      • helloDolin:你好,我Native集成RN后,开发者菜单打不开,有类似的问题么?
        朱_源浩:@helloDolin 谢谢:kissing_closed_eyes:
        helloDolin:哈哈,我自己解决了问题
        Podfile文件里边
        pod 'React', :path => './ReactComponent/node_modules/react-native',:subspecs => []
        是否有DevSupport,没有的话添加进去,然后pod install一下就可以看到开发者菜单了
        我也是刚解决好,过来回复下!
      • 一亩三分甜:你好,请问下,采用这种嵌套方式接入RN,真机和模拟器调试的时候按住cmd + d的方式能调出调试菜单吗?
        一亩三分甜:@helloDolin 解决了,在cocoapods里面加上DevSupport。
        helloDolin:我没有,你与解决么 ?
      • JX_Chanho:集成全部OK了,但是编译报错
        failed to remove /Users/chenhao/Library/Developer/Xcode/DerivedData/TestReactNative-eklhnusnkbwcpncfeouuljaxwcdg/Build/Products/Debug-iphonesimulator/TestReactNative.app/Info.plist: “Info.plist” couldn’t be removed.
      • 6d23394cda62:你好,我想问下,怎么开启项目呢,像之前的react-native run-ios没有用,是不是我进的目录不对
      • 流星留步:请问iOS集成react native无法调出dev menu怎么破?
        一亩三分甜:请问最后有解决吗?我也无法调出dev menu。
        一个努力的boy:这个最后有解决吗,目前我也是这个问题
        朱_源浩:试下pod 版本的 升级
      • 宣文艺的挨踢楠:我的也出问题
      • SDBridge:厉害
      • 大号鱼骨头:Downloading dependencies
        Using React (0.44.0)
        Using Yoga (0.44.0.React)
        Generating Pods project
        Integrating client project
        Sending stats
        Pod installation complete! There are 11 dependencies from the Podfile and 2
        total pods installed.
        俩库都拉下来了,还是报这个错。
        'jschelpers/JavaScriptCore.h' file not found
        不知道是不是版本太高的原因,😓
        uncleRX:@大号鱼骨头 pod 版本的 升级成1.2就可以了
        大号鱼骨头:解决了这个问题。各种修改#import。哎,为啥拉下来的不对呢。奇怪。
      • 74b168ccd3cd:-bash: react-native: command not found 我是没赚哪个环境吗 不能解析
      • FMG:这是什么问题?求助啊。。。
        FMG$ pod install
        Analyzing dependencies
        Fetching podspec for `React` from `./ReactNative/node_modules/react-native`
        [!] Unable to satisfy the following requirements:

        - `React/RCTText (from `./ReactNative/node_modules/react-native`)` required by `Podfile`

        Specs satisfying the `React/RCTText (from `./ReactNative/node_modules/react-native`)` dependency were found, but they required a higher minimum deployment target.
        lee_moons:@FMG 我也是这个问题 这是要更新cocospod吗
        FMG:解决了:podfile 版本号低于xcode版本号
      • 矿工007:您好,请问一下,现在都是Mac启动一个本地服务器拿的代码,要是我上线时不想用服务器代码,怎么把RN代码打包到程序里呢
      • dispatch_async:podfile里面
        # 如果你的RN版本 >= 0.42.0,请加入下面这行
        pod "Yoga", :path => “ ./node_modules/react-native/ReactCommon/yoga"
      • 29bcb36dd6b5:pod install 的时候出问题了。
        [!] Unable to satisfy the following requirements:

        - `Yoga (= 0.42.0.React)` required by `React/Core (0.42.0)`

        None of your spec sources contain a spec satisfying the dependency: `Yoga (= 0.42.0.React)`.

        You have either:
        * out-of-date source repos which you can update with `pod repo update`.
        * mistyped the name or version.
        * not added the source repo that hosts the Podspec to your Podfile.

        Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.


        YoGa是什么?
        大号鱼骨头:'jschelpers/JavaScriptCore.h' file not found
        我的加了yoga的库,报上面的错,不知道啥原因。。
        BSimmons:@冬菇丶蒸鸡肉灬 这个yoga是什么啊
        29bcb36dd6b5:找到解决方法了。要把YoGa 也导进去。。。
        react_native_path = "./dysyjj/Classes/ReactComponent/node_modules/react-native"
        pod "Yoga", :path => "#{react_native_path}/ReactCommon/yoga"
        pod 'React', :path => react_native_path , :subspecs => [
        'Core',
        'ART',
        'RCTActionSheet',
        'RCTAdSupport',
        'RCTGeolocation',
        'RCTImage',
        'RCTNetwork',
        'RCTPushNotification',
        'RCTSettings',
        'RCTText',
        'RCTVibration',
        'RCTWebSocket',
        'RCTLinkingIOS',
        ]
      • 柯丕安德柯丕:pod install已经成功 但是这里报错
        BMNL/ReactComponent/node_modules/react-native/React/Base/RCTConvert.h:13:9: 'yoga/Yoga.h' file not found


        3601593ca2de:我用的是oc,一编译就报错,说找不到,都弄了一天多了:joy:
        柯丕安德柯丕:@哈哈奎奎 暂时没有呢。 我用的是swift 不知道是不是和这个有关系。。。
        3601593ca2de:我也是,你解决了吗?
      • 愚人船ios:是不是只能嵌入一个RN 页面啊 ,可以在两个地方都嵌入吗?
        Clee:应该是可以,不过要拆分成不同的jsbundle
      • Yuency:官网上的教程看了也不懂是怎么一回事.跟着你的步骤做下来成功了,真是太赞了.
      • CowboyBebop:我创建package.json后,npm install,会报下面这个错误
        module.js:471
        throw err;
        ^

        Error: Cannot find module 'semver'

        麻烦大神给看一下,我直接创建RN的项目是没问题的,
        朱_源浩:@CowboyBebop 试试单独npm install semver这个包
      • 19ecfd566409:请教,我#import<RCTRootView.h>的时候,提示找不到应该怎么办啊?发现pod里面也有react了
        肥朝:@OutMan_Coder 同问,我也遇到了这个问题,你们解决了嘛
        OutMan_Coder:@langxulei 我也是相同的问题
        朱_源浩:@langxulei 可能是pod的配置出问题?
      • 心至靜行至遠:Native module cannot be null 怎么破?
      • zeejun_xm:请问下你文中的例子怎么从RN的那个viewcontroller继续push一个RN的viewcontroller?JS里面能获取到NavigatorIOS对象吗?
        朱_源浩:@zeejun_xm rn自身的vc push的话是依靠自己的导航栏组件的吧,有ios专用,也有ios安卓通用的组件。。如果是说push出原生vc的话,则是调用原生方法push,需要注意放主线程里调用才会成功
      • 幻蝶恋影:我的怎么程序跑不起来?
        NSString * strUrl = @"http://192.168.1.124:8081/index.ios.bundle?platform=ios&dev=flase&quot;;
        NSURL * jsCodeLocation = [NSURL URLWithString:strUrl];


        幻蝶恋影:@Azen 3. 启动开发服务器

        在运行我们的项目之前,我们需要先启动我们的开发服务器。进入 reactnative目录 ,然后命令行启动服务:

        react-native start 这个是在哪个目录下执行
        幻蝶恋影:@Azen 好的。谢谢
        Azen:@梦之遥海之蓝
        不用localHost的话,
        ```
        <key>NSAppTransportSecurity</key>
        <dict>
        <key>NSExceptionDomains</key>
        <dict>
        <key>localhost</key>
        <dict>
        <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
        <true/>
        </dict>
        </dict>
        </dict>
        ```
        这坨应该改掉吧.
        改成

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

        这坨试试?
      • Azen:小哥,写的好棒!!!多谢多谢~~
        朱_源浩:@Azen 哈哈哈,nice
        Azen:@朱_源浩 我也是第一次打赏人 ☺️☺️☺️
        朱_源浩:@Azen 第一次有人打赏,谢谢鼓励,超级 :kissing_closed_eyes: :kissing_closed_eyes:
      • vincent涵:请问一个问题,我按照这个流程,我的原项目运行并显示跳转RN界面没问题,但是我修改JS代码(比如去掉一个显示的单词),cmd+r刷新,RN界面并没更新,运行你的DEMO或者运行之前创建的纯RN项目都没问题,请问有没有遇到过知道哪里出问题了
        vincent涵:@朱_源浩 嗯,从昨天下午搞到现在了:joy:,查了好多相似情况解决方法都试了,都不行,好纠结。我再研究研究,谢谢啦
        朱_源浩:@vincent涵 解决不了的哈,这篇文章可以看看
        https://github.com/facebook/react-native/issues/306
        朱_源浩:@vincent涵 我没遇到过。。不过分析下,首先,js文件修改有没按保存(我经常忘记),其次,调试那里设置的模式是debug吗,只有是debug的时候cmd+r刷新才回有效。。目前想到这两个可能性哈
      • 王木木晚安: The dependency `React/RCTWebSocket (from `../ReactComponent/node_modules/react-native`)` is not used in any concrete target.

        创建完Podfile之后 pod install命令提示这样的错误是哪里出问题了啊
        王木木晚安:@朱_源浩 哈哈 谢谢大神,找到问题所在了 :smile: 加油~
        朱_源浩:@早上好王木木 报错原因是所用的库没有指定target,,
        可能是pod版本问题,我的倒没有出现,试试sudo gem install cocoapods --pre升级下pod,
        也可以试试外层加上下面语句
        target 'app名字' do
        pod的具体内容
        end
        王木木晚安:@早上好王木木 路径是正确的检查过了
      • 山是水的故事:请问下你怎么从rn的那个viewcontroller退回来前一个viewcontroller?
        朱_源浩:@山是水的故事 rn的那个viewcontroller是push出来的,导航栏还在,所以直接左上角返回按钮返回就行了啊

      本文标题:7) React Native 集成到原生项目(iOS)

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