美文网首页iOS 功能类
iOS React native混合开发集成及使用

iOS React native混合开发集成及使用

作者: percivals | 来源:发表于2018-05-03 15:45 被阅读445次

本文主要讲述集成React native的过程,以及简单使用的方法,并就过程中遇到的问题进行论述,按照步骤全程走了一遍,亲测可用。闲话不多说,talk is cheap,let's take a look at the code

一、安装npm(已安装请跳过此步)

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

3.检查是否安装成功及版本号

npm -v

二、使用cocoapods集成导入react native

  1. 创建项目ReactNativeTestDemo

  2. 项目主文件夹下新建一个名为package.json的文件和一个index.ios.js的文件

package.json:

 {
  "name": "ReactNativeTestDemo",
  "version": "0.0.1",
  "private": true,
  "scripts": {
  "start": "node node_modules/react-native/local-cli/cli.js start",
  "test": "jest"
  },
  "dependencies": {
  "react": "^16.0.0-alpha.12",
  "react-native": "^0.47.2"
  },
  "devDependencies": {
  "babel-jest": "20.0.3",
  "babel-preset-react-native": "3.0.2",
  "jest": "20.0.4",
  "react-test-renderer": "16.0.0-alpha.12"
  },
  "jest": {
  "preset": "react-native"
  }
 }

index.ios.js

import React, { Component } from 'react';
    import {
     AppRegistry,
     StyleSheet,
     Text,
     View
    } from 'react-native';
    ​
    export default class ReactNativeTestDemo extends Component {
         render() {
             return (
                 <View style={styles.container}>
                     <Text style={styles.welcome}>
                     iOS RN  混合开发的Demo
                     </Text>
                 </View>
             )
         }
    }
    ​
    const styles = StyleSheet.create({
       container: {
           flex: 1,
           justifyContent: 'center',
           alignItems: 'center',
           backgroundColor: '#F5FCFF'
       },
       welcome: {
           fontSize: 20,
           textAlign: 'center',
           margin: 10,
       }
    });
    ​
    AppRegistry.registerComponent('ReactNativeTestDemo', () => ReactNativeTestDemo);
  1. cd到项目主文件夹,执行npm install命令,安装成功后会出现node_modules文件夹 (如果需要更新 执行:react-native upgrade)
   *** 此处如果出现警告需要注意,会影响后续运行效果,上网查询解决办法***
   ​
   例:npm WARN react-native@0.47.2 requires a peer of react@16.0.0-alpha.12 but none is installed. You must install peer dependencies yourself.
   ​
   解决办法:手动更新下载  npm install -save react@16.0.0-alpha.12</pre>
  1. 在项目根目录下执行vim Podfile创建Podfile文件,并执行pod install
  platform :ios, '9.0'
  target "ReactNativeTestDemo" do
  ​
  pod 'Yoga',  :path => ‘./node_modules/react-native/ReactCommon/yoga'
  pod 'React', :path => ‘./node_modules/react-native', :subspecs => [
   'Core',
   'RCTText',
   'RCTImage',
   'RCTAnimation',
   'RCTNetwork’,
   'RCTWebSocket',
   'BatchedBridge' 
  ]
  ​
  end
  1. 添加libraries ,设置网络环境

    使用xcode打开项目, Build phases -> link binary with libraries 添加libReact.a 和 libYoga.a

    plist文件中添加网络允许ATS:

   <key>NSAppTransportSecurity</key>
   ​
    <dict>
   ​
    <key>NSAllowsArbitraryLoads</key>
   ​
    <true/>
   ​
    </dict>
  1. 项目中编写代码逻辑
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8888/index.ios.bundle?platform=ios&dev=true"];
     RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"ReactNativeTestDemo" initialProperties:nil launchOptions:nil];
     rootView.backgroundColor = [UIColor whiteColor];
     rootView.frame = CGRectMake(0, isIphoneX?88:64, KMainScreenW, isIphoneX?KMainScreenH-122:KMainScreenH-64);//简单适配一下iPhone X
     [self.view addSubview:rootView];
  1. cd到项目主目录,执行 react-native start 命令,执行成功后直接运行项目

    可能会遇到Packager can't listen on port 8081 错误,可以尝试以下任一方法:

 一、重启电脑,

 二、查找端口:sudo lsof -i :8081 找到pid数字

 ​ 杀掉端口:sudo kill -9 <pid>

 可能会遇到杀掉占用端口的进程后又被占用的情况,一直重复运行查找-杀进程 直到未被占用,迅速执行 react-native start命令占用此端口,就可以放心测试了😁

 三、更换端口:react-native start --port=8888
  1. 遇到的错误
    错误:  EMFILE: too many open files, watch {"errno":-24,"syscall":"watch","code":"EMFILE","filename":null} Error: EMFILE: too many open files, watch     at FSEvent.FSWatcher._handle.onchange (fs.js:1338:28)
    ​
    解决:  终端  brew install watchman
    ​
    错误:  ReactComponentTreeHook.purgeUnmountedComponents is not a function
    ​
    解决:  npm install安装出现问题,重新安装,注意警告信息
    ​
    另外,注意package.json、index.ios.js等文件中项目名的替换,以及读取文件路径是否正确,react-native start命令是否执行成功

    如果出现红屏问题,根据提示寻找对应解决办法,耐心调试;

    如果运行之后出现了RN界面,并按js文件展示出了对应文字,则为集成成功,可以进行下一步使用了。

9.模拟器里运行到此就ok了,如果想把它装到真机上,这时localhost上的网址就无法访问了,需要生成main.jsbundle

1.在React Native项目node_modules同级目录下运行 npm start

运行成功后会显示  React packager ready.    Loading dependency graph, done.

2.保持终端运行状态,打开新窗口使用curl命令生成 main.jsbundle

curl http://localhost:8081/index.ios.bundle -o main.jsbundle

3.在项目中选择使用main.jsbundle 注释掉

  jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];

改成下面这一行

  jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

三、RN调用原生(Native)

  1. 新建一个继承自NSObject的类 RNToNativeBridgeModule(取名自定义,类似于桥接文件,用于创建方法供js端调用,并完成回调反馈逻辑处理),实现RCTBridgeModule协议

RNToNativeBridgeModule.h

 #import <Foundation/Foundation.h>
 #import <React/RCTBridgeModule.h>
 ​
 @interface RNToNativeBridgeModule : NSObject<RCTBridgeModule>
 ​
 @end

RNToNativeBridgeModule.m

  #import "RNToNativeBridgeModule.h"
  #import <React/RCTBridge.h>
  ​
  @implementation RNToNativeBridgeModule
  ​
  @synthesize bridge = _bridge;
  ​
  RCT_EXPORT_MODULE(RNToNativeBridgeModule);//不加参数也可以,默认导出本身
  ​
  RCT_EXPORT_METHOD(RNToNative:(NSString *)msg){
   dispatch_async(dispatch_get_main_queue(), ^{

  //        NSLog(@"RN传递过来的消息:%@",msg);
   [[NSNotificationCenter defaultCenter] postNotificationName:@"RNToNative" object:msg];

   });
  }
  @end
  1. 修改index.ios.js文件,实现调用逻辑
 import React, { Component } from 'react';
 import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableOpacity,     //新增
  NativeModules,       //新增
 } from 'react-native';
 ​
 var RNToNativeBridgeModule = NativeModules.RNToNativeBridgeModule;  //对象名称可以自己取,跟下面的一致即可
 ​
 export default class ReactNativeTestDemo extends Component {
      render() {
          return (
              <View style={styles.container}>
                  <TouchableOpacity activeOpacity={0.5} onPress={() => RNToNativeBridgeModule.RNToNative('测试一下返回功能')}>
                  <Text style={styles.welcome}>
  点我测试RN调Native!
                  </Text>
                  </TouchableOpacity>
              </View>

          )
      }
 }
 ​
 const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
    }
 });
 ​
 AppRegistry.registerComponent('ReactNativeTestDemo', () => ReactNativeTestDemo);
  1. 在需要的地方监听设置的通知方法,进行逻辑处理

四、原生(Native)调用RN

  1. 建立一个继承自RCTEventEmitter的类 NativeToRNBridgeModule(取名自定义,类似于桥接文件,用于编写逻辑调用RN方法),实现RCTBridgeModule协议

NativeToRNBridgeModule.h

  #import <React/RCTEventEmitter.h>
  ​
  @interface NativeToRNBridgeModule : RCTEventEmitter<RCTBridgeModule>
  +(void)emitEventWithName:(NSString *)name andPayload:(NSDictionary *)payload;
  @end

NativeToRNBridgeModule.m

 #import "NativeToRNBridgeModule.h"
 ​
 @implementation NativeToRNBridgeModule
 ​
 RCT_EXPORT_MODULE() //不加参数默认导出本身
 ​
 - (NSArray<NSString *> *)supportedEvents { //所有需要调用的方法名
  return @[@"NativeToRN"];
 }
 ​
 -(void)startObserving
 {
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitEventInternal:) name:@"event-emitted" object:nil];
 }
 ​
 -(void)stopObserving
 {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
 }
 ​
 //监听通知方法
 -(void)emitEventInternal:(NSNotification *)notify
 {
  //向RN发送消息
  if ([notify.object isKindOfClass:[NSDictionary class]]) {
  NSDictionary *dic = notify.object;
  [self sendEventWithName:@"NativeToRN" body:dic[@"obj"]];  //name 可以自定义,跟js文件及supportedEvents方法里的一致即可
  }
 }
 ​
 +(void)emitEventWithName:(NSString *)name andPayload:(NSDictionary *)payload
 {
  [[NSNotificationCenter defaultCenter] postNotificationName:name object:payload];
 }
 ​
 @end
  1. 修改index.ios.js文件,实现调用逻辑
 import React, { Component } from 'react';
 import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
  NativeModules,
  NativeEventEmitter     //新增
 } from 'react-native';
 ​
 var RNToNativeBridgeModule = NativeModules.RNToNativeBridgeModule;  //对象名称可以自己取,跟下面的一致即可
 var NativeToRNBridge = NativeModules.NativeToRNBridgeModule;
 const Emitter = new NativeEventEmitter(NativeToRNBridge);
 ​
 export default class ReactNativeTestDemo extends Component {
      render() {
          return (
              <View style={styles.container}>
                  <TouchableOpacity activeOpacity={0.5} onPress={() => RNToNativeBridgeModule.RNToNative('测试一下返回功能')}>
                  <Text style={styles.welcome}>
  点我测试RN调Native!
                  </Text>
                  </TouchableOpacity>
              </View>

          )
      }

  componentWillMount() {
      Emitter.addListener('NativeToRN',(body)=>this._getNotice(body));
  }

  _getNotice (body) {
      alert("这是RN弹窗\n" + body);
  }

  componentWillUnMount() {
      this.subScription.remove();
  }

 }
 ​
 const styles = StyleSheet.create({
     container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
    }
 });
 ​
 AppRegistry.registerComponent('ReactNativeTestDemo', () => ReactNativeTestDemo);
  1. 在项目中编写代码调用emitEventWithName方法,发送消息给RN进行尝试

Codepush热更新相关内容见文档https://www.jianshu.com/p/eda2c131734c

新手上路,参照大神们的文档完成的,有不懂的可以看看原文,😁

参考:

https://www.jianshu.com/p/5111312c57b4

https://www.jianshu.com/p/b1ad255bcf47

https://www.jianshu.com/p/572f007fe2c5

https://www.jianshu.com/p/c979024dc62c

相关文章

网友评论

    本文标题:iOS React native混合开发集成及使用

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