欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-29 09:00:39
每种语言都有自己的设计理念、语法、运行环境,这也导致了不同语言间相互交流通信时必须要有中介来翻译,如java与c/c++通过jni来交流、oc与c/c++需要在.mm文件混...

每种语言都有自己的设计理念、语法、运行环境,这也导致了不同语言间相互交流通信时必须要有中介来翻译,如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)
{
 ls*datamode* mode = [[ls*datamode 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之通信机制

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