【React Native】在原生和React Native間通訊(RN調用原生)

1、從React Native中調用原生方法(原生模塊)

  原生模塊是JS中也可使用的Objective-C類。通常來講這樣的每個模塊的實例都是在每一次經過JS bridge通訊時建立的。他們能夠導出任意的函數和常量給React Native。相關細節能夠參閱這篇文章html

  在React Native中,一個「原生模塊」就是一個實現了「RCTBridgeModule」協議的Objective-C類,其中RCT是ReaCT的縮寫。react

// CalendarManager.h
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>

@interface CalendarManager : NSObject <RCTBridgeModule>
@end

  爲了實現RCTBridgeModule協議,你的類須要包含RCT_EXPORT_MODULE()宏。這個宏也能夠添加一個參數用來指定在Javascript中訪問這個模塊的名字。若是你不指定,默認就會使用這個Objective-C類的名字。ios

// CalendarManager.m
@implementation CalendarManager

RCT_EXPORT_MODULE();

@end


//支付寶支付
RCT_EXPORT_METHOD(onAliPay:(NSString *)orderString  resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
  //模塊代碼  
}

  如今從Javascript裏能夠這樣調用這個方法:git

import {
    NativeModules
} from 'react-native';
var pay = NativeModules.ReactNativePay;

 Pay.onAliPay(payStr) .then((message)=>{
      console.log("message" + message); if(message !== "")
        //支付成功的處理
      this.refs.toast.show(message, DURATION.LENGTH_SHORT);
    }) .catch(e=>{
      console.log("e.message" + e.message);
      if(e.message !== "") this.refs.toast.show(e.message, DURATION.LENGTH_SHORT);
      if(e.code === '-1' || e.message === '支付失敗') {
        //支付失敗
      }
    })

  注意: 導出到Javascript的方法名是Objective-C的方法名的第一個部分。React Native還定義了一個RCT_REMAP_METHOD()宏,它能夠指定Javascript方法名。當許多方法的第一部分相同的時候用它來避免在Javascript端的名字衝突。github

2、參數類型

  RCT_EXPORT_METHOD 支持全部標準JSON類型,包括:json

  • string (NSString)
  • number (NSIntegerfloatdoubleCGFloatNSNumber)
  • boolean (BOOLNSNumber)
  • array (NSArray) 包含本列表中任意類型
  • object (NSDictionary) 包含string類型的鍵和本列表中任意類型的值
  • function (RCTResponseSenderBlock)

  除此之外,任何RCTConvert類支持的的類型也均可以使用(參見RCTConvert瞭解更多信息)。RCTConvert還提供了一系列輔助函數,用來接收一個JSON值並轉換到原生Objective-C類型或類。以下:react-native

RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)secondsSinceUnixEpoch)
{
  NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
}

或

RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSString *)ISO8601DateString)
{
  NSDate *date = [RCTConvert NSDate:ISO8601DateString];
}

3、回調函數

  原生模塊還支持一種特殊的參數——回調函數。它提供了一個函數來把返回值傳回給JavaScript。以下:async

typedef void (^RCTResponseSenderBlock)(NSArray *response);

typedef void (^RCTResponseErrorBlock)(NSError *error);

typedef void (^RCTPromiseResolveBlock)(id result);

typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);

 4、實例代碼(一)

  (1)原生代碼函數

//.h文件
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>


@interface RNMethodTool : NSObject <RCTBridgeModule>
@end



//.m文件
#import "RNMethodTool.h"
#import "AppDelegate.h"
@implementation RNMethodTool
//這個宏必需要寫的,不然RN找不到該類
RCT_EXPORT_MODULE()

RCT_EXPORT_METHOD(doSomething:(NSString *)string){
  //這也是暴露給RN的方法,彈出系統框,stirng是RN傳過來的參數
  dispatch_async(dispatch_get_main_queue(), ^{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"我是iOS系統框  RN 調用 原生方法"  message:string preferredStyle:UIAlertControllerStyleAlert];
    
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil];
    
    [alertController addAction:cancelAction];
    [alertController addAction:okAction];
    
    AppDelegate *delegate = (AppDelegate *)([UIApplication sharedApplication].delegate);
    [delegate.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  });
}

@end

  (2)在JS端的應用flex

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View,NativeModules,TouchableHighlight} from 'react-native';
const methodTool = NativeModules.RNMethodTool;

type Props = {};
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        <TouchableHighlight onPress={()=>methodTool.doSomething("我是rn傳過來的數據")}>
          <Text style={styles.welcome}>Welcome to React Native!</Text>
        </TouchableHighlight>
      </View>
    );
  }
  
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

 5、實例代碼(二)

  原生端

//.h文件
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

@interface NativeInteraction : NSObject <RCTBridgeModule>

@end


//.m實現文件
#import "NativeInteraction.h"

#define TestNativeJsonData @"{\"callback1\":\"123\",\"callback2\":\"asd\"}"

@implementation NativeInteraction
{
  RCTPromiseResolveBlock _resolveBlock;
  RCTPromiseRejectBlock _rejectBlock;
}
RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(RNTransferIOS) {
  NSLog(@"RN調用iOS");
}

RCT_EXPORT_METHOD(RNTransferIOSWithParameter:(NSString *)logString) {
  NSLog(@"來自RN的數據:%@",logString);
}

RCT_EXPORT_METHOD(RNTransferIOSWithCallBack:(RCTResponseSenderBlock)callback) {
  callback(@[[NSString stringWithFormat:@"來自iOS Native的數據:%@",TestNativeJsonData]]);
}

RCT_REMAP_METHOD(RNTransferIOSWithParameterAndCallBack, para1:(NSString *)para1 para2:(NSString *)para2 resolver:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)reject) {
  NSLog(@"來自RN的數據:para1——%@, para2——%@",para1, para2);

  _resolveBlock=resolver;
  _rejectBlock=reject;
  NSString *jsonString = TestNativeJsonData;
  _resolveBlock(@[jsonString]);
}


@end

   在JS端的應用

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, DeviceEventEmitter, Alert, Button, NativeModules} from 'react-native';

const NativeInteraction = NativeModules.NativeInteraction;

type Props = {};
export default class App extends Component<Props> {

  constructor(props) {
    super(props);
    this.state = {
        notice: '默認值',
    };
  }

  componentWillMount() {
      DeviceEventEmitter.addListener('EventInit', (msg) => {
          let receive = "EventInit: " + msg;
          console.log(receive);
          this.setState({notice: receive});
      });

      DeviceEventEmitter.addListener('EventLogin', (msg) => {
          let receive = "EventLogin: " + msg;
          console.log(receive);
          this.setState({notice: receive});
      });
  }

  transferIOS = () => {
    NativeInteraction.RNTransferIOS();
  }

  transferIOS1 = () => {
    NativeInteraction.RNTransferIOSWithParameter('{\'para1\':\'rndata1\',\'para2\':\'rndata2\'}');
  }

  transferIOS2 = () => {
    NativeInteraction.RNTransferIOSWithCallBack((data) => {
      this.setState({notice: data});
    });
  }

  transferIOS3 = () => {
    NativeInteraction.RNTransferIOSWithParameterAndCallBack('rndata1','rndata2').then(result =>{
      let jsonString = JSON.stringify(result);
      this.setState({notice: jsonString});
    }).catch(error=>{
    });
  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>第一個React Native頁面</Text>
        <Text style={styles.instructions}>{this.state.notice}</Text>
        <Button
          onPress={this.transferIOS}
          title="RN調用iOS(無回調無參數)"
          color="#841584"
          />
        <Button
          onPress={this.transferIOS1}
          title="RN調用iOS(有參數)"
          color="#841584"
          />
        <Button
          onPress={this.transferIOS2}
          title="RN調用iOS(有回調)"
          color="#841584"
          />
        <Button
          onPress={this.transferIOS3}
          title="RN調用iOS(有參數有回調)"
          color="#841584"
          />
      </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,
  },
});

 

  參考資料:https://www.jianshu.com/p/5f5c50638b2e 感謝這位大佬。

相關文章
相關標籤/搜索