原生模塊是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
RCT_EXPORT_METHOD
支持全部標準JSON類型,包括:json
NSString
)NSInteger
, float
, double
, CGFloat
, NSNumber
)BOOL
, NSNumber
)NSArray
) 包含本列表中任意類型NSDictionary
) 包含string類型的鍵和本列表中任意類型的值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]; }
原生模塊還支持一種特殊的參數——回調函數。它提供了一個函數來把返回值傳回給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);
(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, }, });
原生端
//.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 感謝這位大佬。