深入理解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 相关文章推荐
javascript 设置某DIV区域内的checkbox复选框
Nov 30 Javascript
jQuery EasyUI API 中文文档 - Tabs标签页/选项卡
Oct 01 Javascript
JavaScript通过字符串调用函数的实现方法
Mar 18 Javascript
简单的JS时钟实例讲解
Jan 13 Javascript
BootStrap的弹出框(Popover)支持鼠标移到弹出层上弹窗层不隐藏的原因及解决办法
Apr 03 Javascript
Angular2 环境配置详细介绍
Sep 21 Javascript
js仿小米官网图片轮播特效
Sep 29 Javascript
vue.js计算属性computed用法实例分析
Jul 06 Javascript
解决Vue.js由于延时显示了{{message}}引用界面的问题
Aug 25 Javascript
一次Webpack配置文件的分离实战记录
Nov 30 Javascript
基于vue.js实现分页查询功能
Dec 29 Javascript
vue axios post发送复杂对象问题
Jun 04 Javascript
浅析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
海贼王动画变成“真人”后,凯多神还原,雷利太帅了!
2020/04/09 日漫
php中3种方法统计字符串中每种字符的个数并排序
2012/08/27 PHP
php组合排序简单实现方法
2016/10/15 PHP
php PDO实现的事务回滚示例
2017/03/23 PHP
php 调用百度sms来发送短信的实现示例
2018/11/02 PHP
javascript 获取所有id中包含某关键字的控件的实现代码
2010/11/25 Javascript
修改好的jquery滚动字幕效果实现代码
2011/06/22 Javascript
在js中判断checkboxlist(.net控件客户端id)是否有选中
2013/04/11 Javascript
一个jquery实现的不错的多行文字图片滚动效果
2014/09/28 Javascript
JavaScript学习笔记之内置对象
2015/01/22 Javascript
jQuery实现跟随鼠标运动图层效果的方法
2015/02/02 Javascript
原生JS实现匀速图片轮播动画
2016/10/18 Javascript
获取select的value、text值的简单示例(jquery与javascript)
2016/12/07 Javascript
Angular的事件和表单详解
2016/12/26 Javascript
Angularjs中使用指令绑定点击事件的方法
2017/03/30 Javascript
vue的style绑定background-image的方式和其他变量数据的区别详解
2018/09/03 Javascript
如何制作一个Node命令行图像识别工具
2018/12/12 Javascript
ES6中的类(Class)示例详解
2020/12/09 Javascript
python检测lvs real server状态
2014/01/22 Python
Python爬取京东的商品分类与链接
2016/08/26 Python
ubuntu系统下 python链接mysql数据库的方法
2017/01/09 Python
利用Celery实现Django博客PV统计功能详解
2017/05/08 Python
python中的计时器timeit的使用方法
2017/10/20 Python
python 计算数组中每个数字出现多少次--“Bucket”桶的思想
2017/12/19 Python
10 分钟快速入门 Python3的教程
2019/01/29 Python
python简单区块链模拟详解
2019/07/03 Python
Python多叉树的构造及取出节点数据(treelib)的方法
2019/08/09 Python
Python简单实现词云图代码及步骤解析
2020/06/04 Python
深入浅析css3 中display box使用方法
2015/11/25 HTML / CSS
html5记忆翻牌游戏实现思路及代码
2013/07/25 HTML / CSS
欧洲最大的品牌水上运动服装和设备在线零售商:Wuituit Outlet
2018/05/05 全球购物
如何写自我鉴定
2014/03/19 职场文书
学生会部长竞聘书
2014/03/31 职场文书
商铺租房协议书范本
2014/12/04 职场文书
初三语文教学反思
2016/03/03 职场文书
vue实现锚点定位功能
2021/06/29 Vue.js