React Native 的JS与Oc 通信

JS 调用 OC

  1. 创建一个OC类,实现 RCTBridgeModule 协议。
  • H 头文件
#import <React/RCTBridgeModule.h>
@interface TestObjectForJS : NSObject<RCTBridgeModule>
@end
  • M 文件
#import <React/RCTLog.h>
@implementation TestObjectForJS

RCT_EXPORT_MODULE(TestObject);   //声明导出的模块名

//声明并实现导出的方法(实际上是类方法)
RCT_EXPORT_METHOD(testFunc:(NSString *)first location:(NSString *)second)
{
    NSString *output = [first stringByAppendingString:second];
    RCTLogInfo(@"Pretending to create an event: %@", output);
}
@end
  1. 在JS中调用即可。
import { NativeModules } from 'react-native';
NativeModules.TestObject.testFunc('11', '22')

OC 给JS调用的方法支持的参数类型

RCT_EXPORT_METHOD 支持所有标准 JSON 类型,包括:

  • string (NSString)
  • number (NSInteger, float, double, CGFloat, NSNumber)
  • boolean (BOOL, NSNumber)
  • array (NSArray) 可包含本列表中任意类型
  • object (NSDictionary) 可包含 string 类型的键和本列表中任意类型的值
  • function (RCTResponseSenderBlock)
  • RCTConvert 声明的也都可以支持
  • 以NSDate 为例: JS端, 可以传递 Date 的 getTime() (时间戳)
const date = new Date('1995-12-17T03:24:00');
NativeModules.TestObject.testFunc('11', '22', date.getTime())

也可以传递 Date的 toISOString().

const date = new Date('1995-12-17T03:24:00');
NativeModules.TestObject.testFunc('11', '22', date.toISOString())

而在native端,如果是接收时间戳参数,可以用 NSNumber 或是直接用 NSDate

RCT_EXPORT_METHOD(testFunc:(NSString *)first location:(NSString *)second time:(NSNumber*)time) {
	NSDate * date = [RCTConvert NSDate:time];
	……
}
RCT_EXPORT_METHOD(testFunc:(NSString *)first location:(NSString *)second time:(NSDate*)time)
{
}

如果是接收时间字符串,可以用 NSString 或是直接用 NSDate

RCT_EXPORT_METHOD(testFunc:(NSString *)first location:(NSString *)second time:(NSString*)time)
{
    NSDate * date = [RCTConvert NSDate:time];
}

多参数,可以用 Dictionary 来包装

JS端:

NativeModules.TestObject.testFunc('11', '22', {
  location: '4 Privet Drive, Surrey',
  time: date.getTime(),
  description: '...'
})

Native端:

RCT_EXPORT_METHOD(testFunc:(NSString *)first location:(NSString *)second param:(NSDictionary*)param){
}

Callback参数(由native将数据异步还给 JS)

Native端,函数可以带一个 RCTResponseSenderBlock 类型的callback,将多个数据返还给 JS。

RCT_EXPORT_METHOD(testCallback:(NSString *)first callback:(RCTResponseSenderBlock)callback)
{
    if (callback) {
        callback(@[@(1),@"b", @"afgg"]);
    }
}

PS: native端的callback只能调用一次,否则JS端会报错(如果 testCallback 声明了两个callback参数,那么一个代码分支只能调用其中一个callback)

RCT_EXPORT_METHOD(testCallback:(NSString *)first
                  callback:(RCTResponseSenderBlock)callback
                  callback2:(RCTResponseErrorBlock)callback2)
{
    BOOL b = YES;
    if (b) {
        if (callback) {
            callback(@[@(1),@"b", @"afgg"]);
        }
    }
    else {
        if (callback2) {
            callback2([NSError errorWithDomain:@"hello" code:1001 userInfo:nil]);
        }
    }
}

而在JS端,传入的callback函数可以带任意个参数,个数与 Native端传入的相同(如果JS端多出的声明参数,值会是 undefined

NativeModules.TestObject.testCallback("1", (i, s, s2, i2) => {
        console.log('int='+i) 	//int=1
        console.log('string='+s) 	//string=b
        console.log('string2='+s2) 	//string2=afgg
        console.log(‘int2='+s2)	//int2=undefined
})

RCTEventEmitter 事件发送器

可以在native端发送指定的事件(带有参数)给JS端。 样例代码:

  1. OC类要继承自 RCTEventEmitter
  2. 重写 方法来声明支持的事件id
- (NSArray<NSString *> *)supportedEvents
{
  return @[@"EventReminder"];
}
  1. native端用 sendEventWithName:body: 方法来发送事件和数据
  2. JS端监听事件并获取数据
const eventListener = new NativeEventEmitter(NativeModules.TestObject)
  const listener =  eventListener.addListener("hello", (data) => {
        console.log("hello data="+data)
    })

//用remove 取消监听
listener.remove()

线程

React Native 在一个独立的串行 GCD 队列中调用Native的方法,但这属于实现的细节,并且可能会在将来的版本中改变。 如果要指定 native代码的执行线程,可以重写 methodQueue 方法。

- (dispatch_queue_t)methodQueue
{
  return dispatch_get_main_queue();
}

PS:methodQueue方法会在模块被初始化的时候被执行一次,然后会被 React Native 的桥接机制保存下来。如果要重用队列,要用成员变量保存下来。