Android React Native原生模块与JS模块通信的方法总结

发布时间 - 2026-01-10 22:59:23    点击率:

Android React Native原生模块与JS模块通信的方法总结

前言:

在做React Native开发的时候避免不了的需要原生模块和JS之间进行数据传递,这篇文章将向大家分享原生模块向JS传递数据的几种方式。

方式一:通过Callbacks的方式

说起Callbacks大家都不陌生,它是最常用的设计模式之一。无论是Java,Object-c,C#,还是JavaScript等都会看到Callbacks的身影。

原生模块支持Callbacks类型的参数,该Callbacks对应JS中的function。

在原生模块中:

public class RNTestModule extends ReactContextBaseJavaModule{
  public RNTestModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }
  @Override
  public String getName() {
    return "RNTest";
  }

 @ReactMethod
 public void measureLayout(
   int tag,
   int ancestorTag,
   Callback errorCallback,
   Callback successCallback) {
  try {
   measureLayout(tag, ancestorTag, mMeasureBuffer);
   map.putDouble("relativeX",1);
   map.putDouble("relativeY", 1);
   map.putDouble("width", 2);
   map.putDouble("height",3);
   successCallback.invoke(relativeX, relativeY, width, height);
  } catch (IllegalViewOperationException e) {
   errorCallback.invoke(e.getMessage());   
  }
}

在上述代码中,measureLayout方法的参数中后两个就是Callbacks,当原生模块处理成功时通过successCallback回调来告知JS处理成功的结果,当原生模块发生异常时,则通过errorCallback回调来JS处理异常。

在JS模块中:

RNTest.measureLayout(
 100,
 100,
 (msg) => {
  console.log(msg);
 },
 (x, y, width, height) => {
  console.log(x + ':' + y + ':' + width + ':' + height);
 }
);

上述代码,是在JS模块中调用原生模块的方法measureLayout,同时向它传递了四个参数,后两个是function类型的参数用于接收原生模块的处理结果。

通过上述的方式,JS调用原生模块的measureLayout方法,原生模块则通过errorCallback与successCallbackCallbacks来将处理结果传递到JS。

这种“You call me,I will callback”,的方式小伙伴们都看懂了吧。

方式二:通过Promises的方式

Promises是ES6的一个新的特性,在React Native中你会看到Promises的大量使用。

原生模块也是支持Promises的,这对喜欢使用Promises的小伙伴则是一个很好的消息。

在原生模块中:

public class RNTestModule extends ReactContextBaseJavaModule{
  public RNTestModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }
  @Override
  public String getName() {
    return "RNTest";
  }
  @ReactMethod
  public void measureLayout(
      int tag,
      int ancestorTag,
      Promise promise) {
    try {
      WritableMap map = Arguments.createMap();
      map.putDouble("relativeX",1);
      map.putDouble("relativeY", 1);
      map.putDouble("width", 2);
      map.putDouble("height",3);

      promise.resolve(map);
    } catch (IllegalViewOperationException e) {
      promise.reject(e);
    }
  }
}

上述代码中,measureLayout方法接收的最后一个为Promise,当相应的处理结果出来之后原生模块通过调用Promise的相应方法来向JS模块传递处理成功,或处理失败的数据。

提示:在原生模块中Promise类型的参数要放在最后一位,这样JS调用的时候才能返回一个Promise。

在JS模块中:

async test() {
 try {
  var {
    relativeX,
    relativeY,
    width,
    height,
  } = await RNTest.measureLayout(100, 100);

  console.log(relativeX + ':' + relativeY + ':' + width + ':' + height); 
 } catch (e) {
  console.error(e);
 }
}

在上述代码中,通过ES7的新特性async/await来修饰了test方法,来以同步方式调用原生模块的measureLayout方法,如果原生模块处理成功,

那么JS中relativeX,relativeY,width,height会获得相应的值,如果原生模块处理失败,则会抛出异常。

如果,不希望以同步的形式调用,可以这样写:

test2(){
 RNTest.measureLayout(100,100).then(e=>{
  console.log(e.relativeX + ':' + e.relativeY + ':' + e.width + ':' + e.height);
  this.setState({
   relativeX:e.relativeX,
   relativeY:e.relativeY,
   width:e.width,
   height:e.height,
  })
 }).catch(error=>{
  console.log(error);
 });
}

以上就是通过Promises的方式向JS传递数据的方式,小伙伴们看懂了吗。

上述两种方式,通过Callbacks的方式与通过Promises的方式,都可以向JS模块传递数据,但都是只能传递一次。

如果,你需要多次向JS模块传递数据(如:按键事件)上述方式还是不够好,下面就像大家分享可以多次传递数据的方式。

方式三:通过发送事件的方式

原生模块支持另外一种向JS模块传递数据的方式,通过发送事件的方式。

原生模块,可以向JS传递事件而不要而不需要直接的调用,就像Android中的广播,iOS中的通知中心。

下面就向大家演示通过RCTDeviceEventEmitter,来向JS传递事件。

在原生模块中:

@Override
public void onHandleResult(String barcodeData) {
  WritableMap params = Arguments.createMap();
  params.putString("result", barcodeData);
  sendEvent(getReactApplicationContext(), "onScanningResult", params);
}

private void sendEvent(ReactContext reactContext,String eventName, @Nullable WritableMap params) {
  reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
      .emit(eventName, params);
}

上述代码向JS模块发送了一个名为“onScanningResult”的事件,并携带了“params”作为参数。

在JS模块中:

下面是在JS代码中进行监听原生模块发出的名为“onScanningResult”的事件。

componentDidMount() {
  //注册扫描监听
  DeviceEventEmitter.addListener('onScanningResult',this.onScanningResult);
}
onScanningResult = (e)=> {
  this.setState({
    scanningResult: e.result,
  });
  // DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult);//移除扫描监听
}

在JS中通过DeviceEventEmitter注册监听了名为“onScanningResult”的事件,当原生模块发出名为“onScanningResult”的事件后,绑定在该事件上的onScanningResult = (e)会被回调。

然后通过e.result就可获得事件所携带的数据。

心得:如果在JS中有多处注册了onScanningResult事件,那么当原生模块发出事件后,这几个地方会同时收到该事件。不过大家也可以通过DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult) 来移除对名为“onScanningResult”事件的监听。

另外,JS模块也支持通过Subscribable mixin,也注册监听事件,因为ES6已经不再推荐使用mixin,所以在这里也就不向大家介绍了。

三种方式的优缺点

方式 缺点 优点
通过Callbacks的方式 只能传递一次 传递可控,JS模块调用一次,原生模块传递一次
通过Promises的方式 只能传递一次 传递可控,JS模块调用一次,原生模块传递一次
通过发送事件的方式 原生模块主动传递,JS模块被动接收 可多次传递

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# Android  # React  # Native原生模块与JS模块通信  # React Native JSI实现RN与原生通信的示例代码  # 深入理解React Native原生模块与JS模块通信的几种方式  # ReactNative-JS 调用原生方法实例代码  # 再次谈论React.js实现原生js拖拽效果引起的一系列问题  # 基于React.js实现原生js拖拽效果引发的思考  # 从原生JavaScript到React深入理解  # 是在  # 回调  # 就像  # 大家分享  # 移除  # 看懂  # 来向  # 都是  # 在这里  # 很好  # 小伙伴们  # 放在  # 都不  # 也就  # 你会  # 则是  # 两种  # 中有  # 推荐使用  # 它是 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: js实现获取鼠标当前的位置  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  如何做网站制作流程,*游戏网站怎么搭建?  悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤  Firefox Developer Edition开发者版本入口  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  Mybatis 中的insertOrUpdate操作  如何挑选高效建站主机与优质域名?  Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率  Windows10如何更改计算机工作组_Win10系统属性修改Workgroup  香港服务器WordPress建站指南:SEO优化与高效部署策略  Laravel如何使用.env文件管理环境变量?(最佳实践)  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  怎么用AI帮你设计一套个性化的手机App图标?  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践  香港服务器网站推广:SEO优化与外贸独立站搭建策略  高端企业智能建站程序:SEO优化与响应式模板定制开发  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  PHP 500报错的快速解决方法  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  如何在宝塔面板中创建新站点?  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程  Laravel怎么上传文件_Laravel图片上传及存储配置  网站制作壁纸教程视频,电脑壁纸网站?  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  无锡营销型网站制作公司,无锡网选车牌流程?  Android GridView 滑动条设置一直显示状态(推荐)  Laravel中的withCount方法怎么高效统计关联模型数量  Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中  如何快速查询网址的建站时间与历史轨迹?  如何选择PHP开源工具快速搭建网站?  英语简历制作免费网站推荐,如何将简历翻译成英文?  如何安全更换建站之星模板并保留数据?  Laravel如何与Pusher实现实时通信?(WebSocket示例)  Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出  Laravel事件监听器怎么写_Laravel Event和Listener使用教程  深圳网站制作培训,深圳哪些招聘网站比较好?  Laravel项目怎么部署到Linux_Laravel Nginx配置详解  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  如何将凡科建站内容保存为本地文件?  如何快速搭建二级域名独立网站?