react-native与原生端交互

1,136 阅读3分钟

前言

无论是 flutter 还是 react-native,在开发过程中都避免不了与原生端的交互,因此对其了解是必要的,这里主要介绍 react-native与原生端的交互

react-native向ios端通信

ios端实现

原生需要创建一个继承自NSObject的类(模块),且遵循 RCTBridgeModule 协议

#import <React/RCTBridgeModule.h>
@interface AppEventMoudle : NSObject <RCTBridgeModule>

@end

AppEventMoudle.m文件件中需要导出改模块, 并将创建的方法导出

#import "AppEventMoudle.h"

@implementation AppEventMoudle

// 导出桥接模块, 参数传空或者当前class的类名
// 参数若为空, 默认模块名为当前class类名即AppEventMoudle
RCT_EXPORT_MODULE(AppEventMoudle);

//无参方法
RCT_EXPORT_METHOD(open) {
}

// 带有参数
RCT_EXPORT_METHOD(OpenView:(NSDictionary *)params){
    // 因为是显示页面,所以让原生接口运行在主线程
    dispatch_async(dispatch_get_main_queue(), ^{
        // 在这里可以写需要原生处理的UI或者逻辑
        NSLog(@"params = %@", params);
    });
}

/// 带有回调
RCT_EXPORT_METHOD(OpenView:(NSDictionary *)params, callback:(RCTResponseSenderBlock)callback){
    if (callback) {
        callback(@[params]);
    }
}

注意

桥接到Javascript的方法返回值类型必须是void

React Native的桥接操作是异步的,在queue里面异步执行,所以如果要返回结果给Javascript,就必须通过回调或者触发事件来进行

这里的回调对应于iOS端就是通过block来回调的

RCTBridge

RCTBridge可以说是一个封装类,封装了RCTCxxBridge

我们先看这个文件提供的一些变量和方法

RCTModuleClasses: 主要储存的是我们注册的module, 所有用宏RCT_EXPORT_MODULE()注册的module都会存入这个变量.

RCTGetModuleClasses: 获取RCTModuleClasses里面所有注册的module

RCTBridgeModuleNameForClass: 从一个类获取这个类的名字

RCTVerifyAllModulesExported: 验证我们所写的所有遵守RCTBridgeModule协议的类是否都在我们的管理中

RCTResponseSenderBlock

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

RCTResponseSenderBlockRCTBridgeModule里面提供的block

这个block接受一个数组参数, 代表原生方法的返回结果

线程问题

js代码的执行是在js线程里面,原生模块的执行默认是在一个串行的queue里面异步执行的

对于原生模块的执行来说,默认一个串行的queue是不够的,我们有时候需要指定模块所有任务执行所在的queue

RCT_EXPORT_METHOD(OpenView:(NSDictionary *)params){
    // 因为是显示页面,所以让原生接口运行在主线程
    dispatch_async(dispatch_get_main_queue(), ^{
        // 在这里可以写需要原生处理的UI或者逻辑
        NSLog(@"params = %@", params);
    });
}

react-native端实现

从这里,通过 NativeModules 中介来调用原生中的方法

import {NativeModules} from 'react-native';

export default class App extends Component{
  turnOn = () => {
    //直接调用导出模块的相应方法
    NativeModules.AppEventMoudle.open();
  }
}

ios向react-native端通信

与上面的类似,这里面简介一下,只不过是通过 RCTEventEmitter 来通信

ios原生端

先导入下面框架,继承自 RCTEventEmitter,且遵循 RCTBridgeModule 协议

#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface PushNotificationEventEmitter : RCTEventEmitter<RCTBridgeModule>

@end

.m 文件

@implementation PushNotificationEventEmitter
//模块化导出,如果没名字,就导入当前的class类名
RCT_EXPORT_MODULE();

-(void)operateReactNative {
    //直接发送消息即可,body可以传递数组和字典等比较基础的类型
    [self sendEventWithName:@"operateReactNative" body:nil];
}
@end

react-native端

import {NativeAppEventEmitter} from 'react-native';
export default class App extends Component{
 listenByReactNative = () => {
    //直接调用导出模块的相应方法
    this.webViewListener = NativeAppEventEmitter.addListener('operateReactNative', message => {
        我是原生端传递过来的信息
    })
  }
}