深入理解React Native核心原理之桥接(Bridge)
React Native是一种基于React的JS框架,它可以让你使用JavaScript和React的开发方式来构建iOS和Android的原生应用。这些原生应用实际上是通过React Native桥接(Bridge)在JavaScript和iOS/Android平台之间进行通信和交互的。
什么是React Native桥接(Bridge)?
React Native桥接(Bridge)是一种在JavaScript和iOS/Android原生代码之间使用的桥接技术。它的原理是通过Native Module和JavaScript Module之间的相互调用来实现Native与JavaScript之间的通信和交互。
每个React Native应用都有一个JavaScript环境和一个宿主环境(iOS或Android平台)。JavaScript代码运行在JavaScript环境中,宿主环境则运行原生的iOS或Android代码。桥接技术则起到了连接和沟通这两个环境之间的作用。
Native Module和JavaScript Module的交互
Native Module是一种可以被JavaScript端调用的原生组件。React Native提供了一些默认的Native Module(比如Image、TextInput等),同时也可以自定义Native Module来满足个性化需求。在iOS和Android平台中,Native Module通常是用Objective-C/Swift或Java来实现的。
JavaScript Module则是一种可以被Native端调用的JavaScript组件。React Native应用中的大多数代码都是JavaScript代码,而JavaScript Module是构建这些代码的基础。JavaScript Module使用ES6的语法来定义,然后通过ES6的export关键字进行导出。
Native Module和JavaScript Module的交互是通过React Native桥接(Bridge)实现的。JavaScript端可以使用RCTBridgeModule和RCTXXXEventEmitter(比如RCTDeviceEventEmitter)等类来与Native端进行交互。而Native端则可以使用RCTExportModule和RCTEventDispatcher等类来与JavaScript端进行交互。
区分同步和异步通信
在Native和JavaScript之间的通信中,有同步和异步两种通信方式。
同步通信是指Native端和JavaScript端在执行过程中会相互阻塞,直到通信完成之后才会继续执行。这种方式通常用于Native Module返回结果给JavaScript端使用。
异步通信则是指Native端和JavaScript端可以在执行的同时进行通信。通信完成之后,Native端通常会通过回调函数等方式将结果返回给JavaScript端。
一般来说,我们应该尽量避免使用同步通信方式,因为它会严重影响应用的性能和响应速度。
示例一:Native Module调用JavaScript Module
下面我们来看一个实际的例子,演示如何在Native Module中调用JavaScript Module。
首先我们需要定义一个Native Module(这里以iOS为例):
#import "RCTBridgeModule.h"
@interface MyNativeModule : NSObject <RCTBridgeModule>
@end
@implementation MyNativeModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(callJavaScriptModule:(NSString *)name params:(NSDictionary *)params) {
RCTLogInfo(@"Calling JavaScript Module with name %@ and params %@", name, params);
}
@end
在这个Native Module中,我们定义了一个名为callJavaScriptModule
的方法,在这个方法中,我们打印出调用信息,然后调用JavaScript Module中的一个方法。
然后我们在JavaScript Module中定义一个方法:
const MyJavaScriptModule = {
sayHello: function() {
console.log('Hello from JavaScript Module!');
},
};
export default MyJavaScriptModule;
这个方法可以通过Native Module中的callJavaScriptModule
方法进行调用:
- (void)callMyJavaScriptModule {
[_bridge.eventDispatcher sendAppEventWithName:@"MyEvent" body:@{@"name": @"MyJavaScriptModule", @"method": @"sayHello"}];
}
在这个代码中,我们通过_bridge.eventDispatcher
访问RCTEventDispatcher实例,然后调用sendAppEventWithName
方法发射一个事件(即名称为MyEvent
的事件)到JavaScript模块。这个事件包含两个参数:name
和method
,表示被调用的JavaScript模块的名称和方法名。
我们可以在JavaScript模块中监听这个事件,并做出相应的处理:
import {DeviceEventEmitter} from 'react-native';
import MyJavaScriptModule from '../modules/MyJavaScriptModule';
DeviceEventEmitter.addListener('MyEvent', (event) => {
if (event.name === 'MyJavaScriptModule' && event.method === 'sayHello') {
MyJavaScriptModule.sayHello();
}
});
在这个代码中,我们使用DeviceEventEmitter
监听事件(名称为MyEvent
),并在事件响应函数中判断事件的参数,如果符合条件(即当事件名称为MyJavaScriptModule
,且方法名为sayHello
时),就调用sayHello
方法。
示例二:JavaScript Module调用Native Module
下面我们来看另一个实际的例子,演示如何在JavaScript Module中调用Native Module。
首先我们需要在JavaScript Module中调用Native Module的方法:
import {NativeModules} from 'react-native';
NativeModules.MyNativeModule.callNativeMethod('Hello', (result) => {
console.log(result);
});
在这个代码中,我们先使用NativeModules
模块从全局React Native变量中获取一个名为MyNativeModule
的Native Module。然后我们调用它的callNativeMethod
方法,并传入一个名为Hello
的参数。
callNativeMethod
方法是一个异步的方法,它的第二个参数是一个回调函数,当调用成功并返回结果时,回调函数会被执行,将结果作为参数传入。
然后我们再来看一下在Native Module中实现callNativeMethod
方法的代码:
#import "RCTBridgeModule.h"
@interface MyNativeModule : NSObject <RCTBridgeModule>
@property (nonatomic, copy) RCTPromiseResolveBlock resolve;
@property (nonatomic, copy) RCTPromiseRejectBlock reject;
@end
@implementation MyNativeModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(callNativeMethod:(NSString *)param resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
self.resolve = resolve;
self.reject = reject;
RCTLogInfo(@"Calling Native Method with param %@", param);
}
- (void)callbackWithResult:(NSString *)result {
self.resolve(result);
}
@end
在这个Native Module中,我们定义了一个callNativeMethod
方法,这个方法用于响应来自JavaScript Module的调用。在这个方法中,我们将传入的参数打印出来,并将resolve
和reject
两个回调函数保存下来。resolve
回调函数在调用成功时被调用,reject
回调函数在调用失败时被调用。
此外,我们还定义了一个callbackWithResult
方法,它用于在Native端完成处理后将结果返回给JavaScript端。
我们需要调用这个方法的实际业务代码放在RCT_EXPORT_METHOD(callNativeMethod:(NSString *)param resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
函数里面,并在完成异步处理后主动调用callbackWithResult
函数返回处理结果。
//---------------------------------------------------
// 业务处理代码
//---------------------------------------------------
- (void)doSomethingAsync:(NSString *)param {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 模拟一个异步操作
[NSThread sleepForTimeInterval:1.0f];
NSString *result = [NSString stringWithFormat:@"Result from Native, param=%@", param];
// 完成异步处理后回调
[self callbackWithResult:result];
});
}
这个异步处理在Real Native中实际为异步操作,用这种方式能保证RN与Native互相不阻塞。
总结
React Native桥接(Bridge)是React Native应用中Native端和JavaScript端之间通信的关键。了解React Native桥接的机制,有助于我们更好地理解React Native应用的内部工作原理,同时也有助于我们更好地定位问题和解决问题。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入理解React Native核心原理(React Native的桥接(Bridge) - Python技术站