美文网首页
原生模块提供同步方法给RN调用

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

作者: jayhe | 来源:发表于2020-09-17 18:37 被阅读0次

    最近有个提供给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调用

          本文链接:https://www.haomeiwen.com/subject/fjkryktx.html