沃梦达 / IT编程 / 前端开发 / 正文

深入理解React Native核心原理(React Native的桥接(Bridge)

React Native是一种基于React的JS框架,它可以让你使用JavaScript和React的开发方式来构建iOS和Android的原生应用。这些原生应用实际上是通过React Native桥接(Bridge)在JavaScript和iOS/Android平台之间进行通信和交互的。

深入理解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模块。这个事件包含两个参数:namemethod,表示被调用的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的调用。在这个方法中,我们将传入的参数打印出来,并将resolvereject两个回调函数保存下来。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)