美文网首页我爱编程
RN与JS交互之-封装iOS原生模块

RN与JS交互之-封装iOS原生模块

作者: lzh_coder | 来源:发表于2017-11-11 10:05 被阅读275次

    本文要讲的交互场景是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类型或类。


    相关文章

      网友评论

        本文标题:RN与JS交互之-封装iOS原生模块

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