React Native 与 OC 之间通信那些事儿

作者:朱灵子

React Native用IOS自带的JavaScriptCore作为JS的解析引擎,普通的JS-OC通信就是React Native在OC定义一个模块方法,JS可以直接调用这个模块方法并还可以无缝衔接回调。

具体的接口调用实现方法如下所示:

  • 将OC注册进来的模块取出,调用模块中的对应函数,且将参数传入 var RCTVideo = require('react-native').NativeModules.RCTVideo; RCTVideo.addVideoTitle('video title');
  • 利用回调参数得到访问OC的函数,并得到其返回值

RCTVideo.RNCallbackEvent('dsb',(error,callBackEvents)=>{
   if (error) {
       console.error(error);
   } else {
       AlertIOS.alert('返回值:'+JSON.stringify(callBackEvents));
   }
});

  • 利用回调参数得到访问OC的函数,并得到其返回值 callback函数:第一个参数是一个错误对象(没有发生错误的时候为null),而剩下的部分是函数的返回值。RCTVideo.RNCallbackEvent('dsb',(error,callBackEvents)=>{ if (error) { console.error(error); } else { AlertIOS.alert('返回值:'+JSON.stringify(callBackEvents)); } });
  • 如果想要OC访问JS,我们需要利用 NativeAppEventEmitter组件,利用其addListener进行注册监听

let ocFun = NativeAppEventEmitter.addListener(
  'eventName',
  (para) => AlertIOS.alert('被OC触发','字典数据:\n name:'+para.name+'\n age:'+para.age)
);

ocFun : 将绑定好的监听事件引用交给此变量保存。

addListener:

第一个参数:事件名

第二个参数:响应函数

注意:利用addListener进行监听,一定要对应有取消监听!

且通常取消监听都在componentWillUnmount函数中进行。如下:

  componentWillUnmount(){
    ocFun.remove();
  }

  • 如何用js构建native封装好的本地UI组件 简单地封装一个native封装好的本地视频组建的实现方法如下:var { requireNativeComponent } = require('react-native'); module.exports = requireNativeComponent('RCTVideo', null);现在这是 JavaScript 中一个功能完整的 native video视图组件了,包括 pinch-zoom 和其他 native 手势支持, 但是我们还不能用 JavaScript 来真正的控制它,所以接下来我们需要给组建添加属性和方法,具体示例如下:class VideoView extends React.Component { constructor() { this.play = this.play.bind(this); } play = (event) => { if (this.props.play) { this.props.play(event.nativeEvent); } } render() { return ( <View> <RCTVideo {...this.props} style = {styles.fullscreen} /> </View> ) } } VideoView.propTypes = { src: React.PropTypes.string, play:React.PropTypes.func, }; var RCTVideo = requireNativeComponent('RCTVideo', VideoView, nativeOnly: { src: true, play: true, } )接下来看看其实现原理,理解react native与OC之间的通信我们首先需要了解模块配置表,接下来对模块配置表进行简单的介绍:模块配置表js如果要调用oc提供的接口方法,OC首先需要向JS传递它所有的模块信息。这里的具体实现方法是OC生成一份模块配置表传给JS,配置表里包括了所有模块和模块里方法的信,具体信息如下所示:{ "remoteModuleConfig": { "RCTVideo": { "methods": { "play": { "type": "remote", "methodID": 0 } }, "moduleID": 4 }, ... }, }OC与js之间的调用流程OC端和JS端分别各有一个bridge,两个bridge都保存了同样一份模块配置表,JS调用OC模块方法时,通过bridge里的配置表把模块方法转为模块ID和方法ID传给OC,OC通过bridge的模块配置表找到对应的方法执行之,以上述代码为例,流程大概是这样(先不考虑callback):
    接下来看看JS调用OC模块方法的详细流程,包括callback回调,下面展示的是细化版本的调用流程图:
    详细说明下这些步骤:
  • 1.JS端调用某个OC模块暴露出来的方法

  • 2.把上一步的调用分解为ModuleName,MethodName,arguments,再扔给MessageQueue处理。 在初始化时模块配置表上的每一个模块都生成了对应的remoteModule对象,对象里也生成了跟模块配置表里一一对应的方法,这些方法里可以拿到自身的模块名,方法名,并对callback进行一些处理,再移交给MessageQueue。
  • 3.在这一步把JS的callback函数缓存在MessageQueue的一个成员变量里,用CallbackID代表callback。在通过保存在MessageQueue的模块配置表把上一步传进来的ModuleName和MethodName转为ModuleID和MethodID。

  • 4.把上述步骤得到的ModuleID,MethodId,CallbackID和其他参数argus传给OC。
  • 5.OC接收到消息,通过模块配置表拿到对应的模块和方法。

  • 6.RCTModuleMethod对JS传过来的每一个参数进行处理。
  • 7.OC模块方法调用完,执行block回调。

  • 8.调用到第6步说明的RCTModuleMethod生成的block。
  • 9.block里带着CallbackID和block传过来的参数去调JS里MessageQueue的方法invokeCallbackAndReturnFlushedQueue。

  • 10.MessageQueue通过CallbackID找到相应的JS callback方法。
  • 11.调用callback方法,并把OC带过来的参数一起传过去,完成回调。

概括一下整体流程如下

整个流程就是这样,简单概括下,差不多就是:JS函数调用转ModuleID/MethodID -> callback转CallbackID -> OC根据ID拿到方法 -> 处理参数 -> 调用OC方法 -> 回调CallbackID -> JS通过CallbackID拿到callback执行

参考文献

原文链接:http://ivweb.io/topic/58227ac90fea59e31b98bb5d

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏逆向技术

PE格式第六讲,导出表

                PE格式第六讲,导出表 请注意,下方字数比较多,其实结构挺简单,但是你如果把博客内容弄明白了,对你受益匪浅,千万不要看到字...

1646
来自专栏Java帮帮-微信公众号-技术文章全总结

Web-第十二天 el&jstl表达式学习

在JSP开发中,为了获取Servlet域对象中存储的数据,经常需要书写很多Java代码,这样的做法会使JSP页面混乱,难以维护,为此,在JSP2.0规范中提供了...

931
来自专栏JarvanMo的IT专栏

Dart In Action -Dart快速入门(五)

本文基本上是将dart官网部分内容进行翻译,没兴趣的请出门左转至Dart的官网,有兴趣的同志请继续阅读本文。 Flutter教程在这里

1143
来自专栏debugeeker的专栏

《coredump问题原理探究》Linux x86版4.4节函数的逆向之循环结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

772
来自专栏大数据挖掘DT机器学习

Python]新手写爬虫全过程(已完成)

今天早上起来,第一件事情就是理一理今天该做的事情,瞬间get到任务,写一个只用python字符串内建函数的爬虫,定义为v1.0,开发中的版本号定义为v0.x。数...

3579
来自专栏听雨堂

用Layer.search快速查询图元

    Mapx中查找图元,用Layer.search来完成;     Layer.search支持用比较表达式来进行查询;但是,往往会报告变量不存在。原因在于...

18910
来自专栏一“技”之长

iOS9系列专题五——全新的联系人与联系人UI框架

        在以前iOS开发中,涉及联系人相关的编程,代码都非常繁琐,并且框架的设计也不是Objective-C风格的,这使开发者用起来非常的难受。在iOS...

634
来自专栏Scott_Mr 个人专栏

React Native 系列(一) -- JS入门知识

34110
来自专栏林德熙的博客

WPF 开发

如果使用NamedPipeServerStream、Mutex做单实例,需要传入字符串,这时如果传入一个固定的字符串,会在多用户的时候无法使用。

491
来自专栏一个会写诗的程序员的博客

Spring Boot 中文乱码问题解决方案汇总

使用 Spring Boot 开发,对外开发接口供调用,传入参数中有中文,出现中文乱码,查了好多资料,总结解决方法如下:

611

扫码关注云+社区