深入理解React Native原生模块与JS模块通信的几种方式


Posted in Javascript onJuly 24, 2017

每种语言都有自己的设计理念、语法、运行环境,这也导致了不同语言间相互交流通信时必须要有中介来翻译,如JAVA与C/C++通过JNI来交流、OC与C/C++需要在.mm文件混编、而JAVA/OC与Lua通信时需要通过C/C++语言来做中介。那么在React-Native中JSX是如何与底层模块进行通信的呢?这里主要以iOS系统来做说明。

原理

通信本质上是信息的交流,具体到计算机语言则是数据的流动。应用中数据在React-Native与原生模块间的流动与共享,完成了与用户的交互,达成了应用的目标。React-Native与OC间通信的数据只能是下面的几种类型(前为JS类型,后为OC类型):

  1. string-NSString
  2. number - int/NSInteger/float/double/NSNumber
  3. boolean - BOOL/NSNumber
  4. array - NSArray
  5. object - NSDictionary(NSString型key, value可以为这里的其它类型)
  6. func - RCTResponseSenderBlock

其它类型的数据需要通过一定的规则转换成这几种类型后(一般都会转换成JSON串)再通信.

React-Native本质是通过JavaScriptCore.framework实现JS代码与OC代码间的互动。因此下面说的几种方式在本质原理上都是相同的,不同的地方只是在于实现形式与方法的差别。

函数调用

在将原生模块封装并提供给React-Native使用时,可以通过RCT_EXPORT_METHOD()宏向React-Native侧定义其可以调用的接口函数,完成两模块间的通信。

//定义了startVPN接口,React-Native将VPN的具体参数通过该接口传入到原生模块,开启指定的VPN
RCT_EXPORT_METHOD(startVPN:(NSDictionary*)config)
{
 LSShadowSocksDataMode* mode = [[LSShadowSocksDataMode alloc] initWithDictionary:config];
 [self.manager startVPN:mode];
}

除了传入数据外,通过可以通过这种方式从原生侧获取数据。最容易想到的是通过返回值获取,可惜的是RCT_EXPORT_METHOD宏不支持返回值,不过其提供了另外一种实现返回值的方式:

RCT_EXPORT_METHOD(isOpen:(RCTResponseSenderBlock)callback)
{
 BOOL open = [self.manager status];
 callback(@[[NSNull null], @[@(open)]]);
}

通过回调函数的形式实现返回值的效果,达到了数据交换的目的。

属性共享

这种方式主要针对于UI控件来说的。React-Native中最基础的UI类型是RCTRootView,该类有一个初始化方法initWithBridge:moduleName:initialProperties:,第三个参数initialProperties表示的是UI控件的初始属性值,类型为NSDictionary,其最终会被同步到由第二个参数定义的React-Native类的props中,即完成了两个模块间的数据交流。

NSArray *imageList = @[@"http://foo.com/bar1.png",
     @"http://foo.com/bar2.png"];

NSDictionary *props = @{@"images" : imageList};

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
          moduleName:@"ImageBrowserApp"
          initialProperties:props];
import React, { Component } from 'react';
import {
 AppRegistry,
 View,
 Image,
} from 'react-native';

class ImageBrowserApp extends Component {
 renderImage(imgURI) {
 return (
  <Image source={{uri: imgURI}} />
 );
 }
 render() {
 return (
  <View>
  {this.props.images.map(this.renderImage)}
  </View>
 );
 }
}

AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);

初始化接口只能在UI组件建立时使用,如果需要在UI组件的生命周期内通信呢,RCTRootView提供了appProperties这样一种机制:

NSArray *imageList = @[@"http://foo.com/bar3.png",
     @"http://foo.com/bar4.png"];
rootView.appProperties = @{@"images" : imageList};

通知

OC中使用NSNotificationCenter向整个应用发送通知,所有对该通知感兴趣的对象都会获得该通知并执行相应的动作。

React-Native中也提供有类似的机制:RCTEventEmitter。原生模块继承该类后,就可以向React-Native侧发送通知,而React-Native就能够接收到该通知,并处理一并传送过来的数据了。

-(void)vpnStatusChanged:(NSNotification*)notification
{
 NEVPNStatus status = [self.manager status];
 NSString* value = nil;
 switch (status) {
 case NEVPNStatusReasserting:
  value = @"重新连接中";
  break;
 case NEVPNStatusConnecting:
  value = @"连接中";
  break;
 case NEVPNStatusConnected:
  value = @"已连接";
  break;
 case NEVPNStatusDisconnecting:
  value = @"断开连接中";
  break;
 case NEVPNStatusDisconnected:
 case NEVPNStatusInvalid:
  value = @"末连接";
  break;
 default:
  break;
   }
 if(value){
 [self sendEventWithName:@"VpnStatus" body:@{@"status":value}];
 }
}

这里将VPN的状态通过通知发送到React-Native侧,由React-Native将VPN的状态显示的UI界面上。

小结

这里只是简单的介绍了两种语言间几种常用的通信方式,并没有涉及到其背后的实现细节。对这方面感兴趣的同学,不妨参阅下面的两篇文章:

React Native通信机制详解

浅析ReactNative之通信机制

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的当鼠标滚轮到最底端继续加载新数据思路分享(多用于微博、空间、论坛 )
Oct 10 Javascript
关于scrollLeft,scrollTop的浏览器兼容性测试
Mar 19 Javascript
Javascript实现简单的富文本编辑器附演示
Jun 16 Javascript
基于jquery实现导航菜单高亮显示(两种方法)
Aug 23 Javascript
JS判断当前页面是否在微信浏览器打开的方法
Dec 08 Javascript
深入解析JavaScript中的立即执行函数
May 21 Javascript
Highcharts学习之坐标轴
Aug 02 Javascript
用jQuery.ajaxSetup实现对请求和响应数据的过滤
Dec 20 Javascript
AngularJS Toaster使用详解
Feb 24 Javascript
vue实现百度下拉列表交互操作示例
Mar 12 Javascript
微信小程序picker组件关于objectArray数据类型的绑定方法
Mar 13 Javascript
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
Apr 11 Vue.js
浅析JavaScript中的平稳退化(graceful degradation)
Jul 24 #Javascript
vue.js移动端app实战1:初始配置详解
Jul 24 #Javascript
React 子组件向父组件传值的方法
Jul 24 #Javascript
浅谈Node.js ORM框架Sequlize之表间关系
Jul 24 #Javascript
vue 实现 tomato timer(蕃茄钟)实例讲解
Jul 24 #Javascript
jQuery实现拼图小游戏(实例讲解)
Jul 24 #jQuery
php register_shutdown_function函数详解
Jul 23 #Javascript
You might like
精致的人儿就要挑杯子喝咖啡
2021/03/03 冲泡冲煮
php错误级别的设置方法
2013/06/17 PHP
使用pthreads实现真正的PHP多线程(需PHP5.3以上版本)
2014/05/05 PHP
Yii2使用小技巧之通过 Composer 添加 FontAwesome 字体资源
2014/06/22 PHP
Jquery CheckBox全选方法代码附js checkbox全选反选代码
2010/06/09 Javascript
基于jquery的代码显示区域自动拉长效果
2011/12/07 Javascript
javascript event在FF和IE的兼容传参心得(绝对好用)
2014/07/10 Javascript
超级好用的jQuery圆角插件 Corner速成
2014/08/31 Javascript
基于JavaScript操作DOM常用的API小结
2015/12/01 Javascript
javascript常用的设计模式
2017/02/09 Javascript
JavaScript中三种常见的排序方法
2017/02/24 Javascript
浅谈node中的exports与module.exports的关系
2017/08/01 Javascript
浅谈基于Vue.js的移动组件库cube-ui
2017/12/20 Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
2017/12/28 Javascript
Node.js原生api搭建web服务器的方法步骤
2019/02/15 Javascript
原生JS实现随机点名项目的实例代码
2019/04/30 Javascript
nodejs实现用户登录路由功能
2019/05/22 NodeJs
PyQt 线程类 QThread使用详解
2017/07/16 Python
python读取一个目录下所有txt里面的内容方法
2018/06/23 Python
详解Python3网络爬虫(二):利用urllib.urlopen向有道翻译发送数据获得翻译结果
2019/05/07 Python
linux环境下Django的安装配置详解
2019/07/22 Python
Python解析json代码实例解析
2019/11/25 Python
Python+opencv+pyaudio实现带声音屏幕录制
2019/12/23 Python
Python3.9.0 a1安装pygame出错解决全过程(小结)
2021/02/02 Python
HTML5实现移动端点击翻牌功能
2020/10/23 HTML / CSS
Orlebar Brown官网:设计师泳裤和泳装
2020/12/08 全球购物
27个经典Linux面试题及答案,你知道几个?
2013/01/10 面试题
会计实习生工作总结的自我评价
2013/10/07 职场文书
全运会口号
2014/06/20 职场文书
十佳少先队员演讲稿
2014/09/12 职场文书
学生检讨书如何写
2014/10/30 职场文书
4S店客服专员岗位职责
2015/04/07 职场文书
《叶问2》观后感
2015/06/15 职场文书
听证会主持词
2015/07/03 职场文书
MySQL高级进阶sql语句总结大全
2022/03/16 MySQL
vscode远程免密登入Linux服务器的配置方法
2022/06/28 Servers