RN与JS交互之-封装iOS原生模块
本文要讲的交互场景是JS调用原生方法,最后由原生方法将结果回调到JS里面。
react-native是在原生的基础上,将接口调用统一为js。也就是说,react-native调起原生的能力非常重要。
本文基于react-native 0.44.3
1,引入头文件
#import <React/RCTBridgeModule.h>
2,遵守协议
@interface BaseNativeModule : NSObject <RCTBridgeModule>
3,导出模块
@implementation BaseNativeModule
RCT_EXPORT_MODULE( moduleName ); //用于导出模块,可以设置导出的模块名,默认就是类名。
@end
4,导出方法:
RCT_EXPORT_METHOD(addEvent:(NSString*)name location:(NSString*)location)
{
//在js控制台上打印log信息。
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
这个方法是一个实例方法。
5,js端调用。
import { NativeModules } from 'react-native
NativeModules.XXX.addEvent( param1, param2 );
需要注意,jsbundle加载需要一个js线程,在jsbundle加载的时候,react-native会去配置NativeModules,它是一个对象,或者看成是一个map,key就是模块名,value就是原生的对象。一个key对应的原生对象只有一个,也就是说无论在RN页面的哪个地方调用这个原生模块,实际调用的是同一个对象,需要考虑对象状态的问题。
6,js回调
桥接到Javascript的方法返回值类型必须是void。React Native的桥接操作是异步的,在queue里面异步执行,所以如果要返回结果给Javascript,就必须通过回调或者触发事件来进行。这里讲的是回调。回调对应于iOS端就是通过block来回调的。
js回调的特点,发起方是js,必须是js端先发起,然后由native方回调结果到js端处理。
6.1 RCTResponseSenderBlock
这个block接受一个数组参数,数组里面有两个元素,第一个参数用于表示错误信息,第二个参数可以是一个数组,也可以是一个对象,总之第二个代表原生方法的返回结果,第一个代表获取成功还是失败。
6.2 Promise样式的回调。一般用于js端try-catch结构,和Promise调用。
RCTPromiseResolveBlock,对应js里面的resolve。
RCTPromiseRejectBlock,对应js里面的reject。
7,多线程
js代码的执行是在js线程里面,原生模块的执行默认是在一个串行的GCD queue里面异步执行的。对于原生模块的执行来说,默认一个串行的GCD queue是不够的,我们有时候需要指定模块所有任务执行所在的queue。
这个可以通过重写methodQueue的getter方法
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
此外,如果一个模块里面的几个任务,个别任务需要在一个特殊的线程里面执行,那么只去在任务执行的逻辑里面,指定该任务执行所在的线程。
RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock) callback)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
// 在这里执行长时间的操作...
// 你可以在任何线程/队列中执行回调函数callback(@[...]); });
}
在模块之间共享分发队列:
methodQueue方法会在模块被初始化的时候被执行一次,然后会被React Native的桥接机制保存下来,所以你不需要自己保存队列的引用,除非你希望在模块的其它地方使用它。但是,如果你希望在若干个模块中共享同一个队列,则需要自己保存并返回相同的队列实例;仅仅是返回相同名字的队列是不行的。
8,参数类型转换。
js与原生互相调用,除了方法签名的不同,参数类型也是不同的,要把参数类型对应起来。react-native框架本身做了一些转换。包括下面这些:
string (NSString)
number ( NSInteger, float, double, CGFloat, NSNumber)
boolean (BOOL,NSNumber)
array (NSArray) 包含本列表中任意类型
object (NSDictionary) 包含string类型的键和本列表中任意类型的值
function (RCTResponseSenderBlock)
除此以外,任何RCTConvert类支持的的类型也都可以使用(参见RCTConvert了解更多信息)。RCTConvert还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。