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执行

参考文献

感谢您的阅读~~~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一枝花算不算浪漫

[数据库连接池] Java数据库连接池--DBCP浅析.

36614
来自专栏Hellovass 的博客

社交化分享组件踩坑

问题是这样的,项目里的社交化分享是基于 UMShare 封装成的一个 ShareLib module,为了让这个 module 对调用者说更透明,我将 WXEn...

2195
来自专栏坚毅的PHP

jersey处理支付宝异步回调通知的问题:java.lang.IllegalArgumentException: Error parsing media type 'application/x-www

tcpflow以流为单位分析请求内容,非常适合服务器端接口类服务查问题 这次遇到的问题跟支付宝支付后的回调post结果有关 淘宝的代码例子: publi...

5235
来自专栏PPV课数据科学社区

【大数据问答】R语言如何导入其他统计软件中的数据?

R语言如何导入其他统计软件中的数据? R导入SAS数据集可以使用 foreign 包中的 read.ssd() 和 Hmisc 包中的 sas.get() 。...

2943
来自专栏实战docker

修改,编译,GDB调试openjdk8源码(docker环境下)

在上一章《在docker上编译openjdk8》里,我们在docker容器内成功编译了openjdk8的源码,有没有读者朋友产生过这个念头:“能不能修改open...

4559
来自专栏大内老A

ASP.NET MVC集成EntLib实现“自动化”异常处理[实例篇]

个人觉得异常处理对于程序员来说是最为熟悉的同时也是最难掌握的。说它熟悉,因为仅仅就是try/catch/finally而已。说它难以掌握,则是因为很多开发人员却...

19710
来自专栏Ceph对象存储方案

Bluestore下的OSD开机自启动分析

整个Bluestore现在由官方推出的ceph-volume工具进行管理,用以替代之前的ceph-disk。回顾之前ceph-disk是通过在xfs文件系统中打...

3644
来自专栏cloudskyme

网页中显示xml,直接显示xml格式的文件

第一种方法 使用<pre></pre>包围代码(在浏览器中测试不行啊,但是在富编辑器中又可以,怪); 使用<xmp></xmp>包围代码(官方不推荐,但是效果不...

4197
来自专栏逸鹏说道

9.数据库服务器部署之------3步实现远程访问

平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html#iis 原文:htt...

3396
来自专栏木木玲

Netty 那些事儿 ——— 心跳机制

5389

扫码关注云+社区