【React Native】在原生和React Native间通信(RN调用原生)
一、从React Native中调用原生方法(原生模块)
原生模块是JS中也可以使用的Objective-C类。一般来说这样的每一个模块的实例都是在每一次通过JS bridge通信时创建的。他们可以导出任意的函数和常量给React Native。相关细节可以参阅这篇文章。
在React Native中,一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类,其中RCT是ReaCT的缩写。
// CalendarManager.h #import <React/RCTBridgeModule.h> #import <React/RCTLog.h> @interface CalendarManager : NSObject <RCTBridgeModule> @end
为了实现RCTBridgeModule
协议,你的类需要包含RCT_EXPORT_MODULE()
宏。这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字。
// CalendarManager.m @implementation CalendarManager RCT_EXPORT_MODULE(); @end //支付宝支付 RCT_EXPORT_METHOD(onAliPay:(NSString *)orderString resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { //模块代码 }
现在从Javascript里可以这样调用这个方法:
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端的名字冲突。
二、参数类型
RCT_EXPORT_METHOD
支持所有标准JSON类型,包括:
- string (
NSString
) - number (
NSInteger
,float
,double
,CGFloat
,NSNumber
) - boolean (
BOOL
,NSNumber
) - array (
NSArray
) 包含本列表中任意类型 - object (
NSDictionary
) 包含string类型的键和本列表中任意类型的值 - function (
RCTResponseSenderBlock
)
除此以外,任何RCTConvert
类支持的的类型也都可以使用(参见RCTConvert
了解更多信息)。RCTConvert
还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。如下:
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。如下:
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端的应用
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 感谢这位大佬。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具