原生模块提供同步方法给RN调用

最近有个提供给RN的库需要提供同步的方法,我想当然的以为用callback的方式,在当前线程同步调用原生逻辑之后,将结果callback回去就可以实现了,结果实际调试起来发现是想当然了

原生提供给JS调用并返回数据的几种方式

Promise

RCT_EXPORT_METHOD(promiseGetItem:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
    // do sth
    if (resolve) {
        resolve(@"222");
    }
}

Callback

RCT_EXPORT_METHOD(callbackGetItem:(NSString *)key callback:(RCTResponseSenderBlock)callback) {
    // do sth
    if (callback) {
        callback(@[@"222"]);
    }
}

BLOCKING_SYNCHRONOUS

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(syncGetItem:(NSString *)key) {
    // do sth
    return @"222";
}

Android的同步方式也贴一下代码

@ReactMethod(isBlockingSynchronousMethod = true)
public String syncGetItem(String key) {
    return "222";
}

直接上结论,BLOCKING_SYNCHRONOUS的方式是可以做到同步的,另外的方式程序执行不会等结果返回,会继续执行后面的逻辑,不符合预期。

分析下为什么

为什么了?看到是一堆的宏,我们将其展开


图片.png

展开之后的代码片段

@implementation TestModule

extern __attribute__((visibility("default"))) void RCTRegisterModule(Class); + (NSString *)moduleName { return @""; } + (void)load { RCTRegisterModule(self); }

+ (const RCTMethodInfo *)__rct_export__140 { static RCTMethodInfo config = {"", "promiseGetItem:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject", __objc_no}; return &config; } - (void)promiseGetItem:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject ; {

    if (resolve) {
        resolve(@"222");
    }
}

+ (const RCTMethodInfo *)__rct_export__211 { static RCTMethodInfo config = {"", "callbackGetItem:(NSString *)key callback:(RCTResponseSenderBlock)callback", __objc_no}; return &config; } - (void)callbackGetItem:(NSString *)key callback:(RCTResponseSenderBlock)callback ; {

    if (callback) {
        callback(@[@"222"]);
    }
}

+ (const RCTMethodInfo *)__rct_export__282 { static RCTMethodInfo config = {"", "syncGetItem:(NSString *)key", __objc_yes}; return &config; } - (id)syncGetItem:(NSString *)key ; {

    return @"222";
}

@end

观察差别,是config的最后一个参数BLOCKING_SYNCHRONOUS方式传的是__objc_yes其他的传的是__objc_no,我们看下config的定义

typedef struct RCTMethodInfo {
  const char *const jsName;
  const char *const objcName;
  const BOOL isSync;
} RCTMethodInfo;

这里就很明显了,最后那个参数就是标记方法是同步还是异步的了;
我们再看它是怎么做到的,我截取了js调用原生方法的一个入口函数的部分代码,方法的具体实现在RCTModuleMethod.mm文件中

- (id)invokeWithBridge:(RCTBridge *)bridge
                module:(id)module
             arguments:(NSArray *)arguments {
    // 此处省略很多代码
   [_invocation invokeWithTarget:module];
   if (_methodInfo->isSync) {
    void *returnValue;
    [_invocation getReturnValue:&returnValue];
    return (__bridge id)returnValue;
  }
  return nil;
}

可以看到,当方法是isSync的时候,调用之后,就获取返回值,并返回回去了,否则就直接返回nil,那么像Promise、Callback的方式结果就不是立马返回的,而是最终等到原生执行逻辑之后手动触发回掉之后返回。

你可能感兴趣的:(原生模块提供同步方法给RN调用)