【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信
一用到跨平台的引擎必然要有引擎与各平台原生进行交互通信的需要。那么Himi先讲解React Native与iOS之间的通信交互。
本篇主要分为两部分讲解:(关于其中讲解的OC语法等不介绍,不懂的请自行学习)
1. React Native 访问iOS
2. iOS访问React Native
一:React Native 访问iOS
1. 我们想要JS调用OC函数,就要实现一个“RCTBridgeModule”协议的Objective-C类
所以首先我们先创建一个oc新类, Himi这里起名为:TestOJO (O: object-c, J: javaScript )
2. TestOJO.h
#import <Foundation/Foundation.h> #import "RCTBridgeModule.h"@interface TestOJO : NSObject <RCTBridgeModule>@end
引入:#import “RCTBridgeModule.h” 且使用 <RCTBridgeModule> 接口,
3. 为了实现RCTBridgeModule协议,类需要包含RCT_EXPORT_MODULE()宏(这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字。)
4. 在TestOJO.m中添加如下:
RCT_EXPORT_MODULE(); //桥接到Javascript的方法返回值类型必须是void。React Native的桥接操作是异步的,所以要返回结果给Javascript,必须通过回调或者触发事件来进行 RCT_EXPORT_METHOD(j2oFun1:(NSString *)dataString dateNumber:(int)dateNumber) {NSLog(@"js call iOS function j2oFun1\n dataString: %@ |dateNumber :%d",dataString,dateNumber); }
想要将oc的函数导出给js进行调用,那么就需要进行声明。声明通过RCT_EXPORT_METHOD()宏来实现:
j2oFun1:函数名,后续是两个参数,分别是NSString 和 int 类型数据。
调用成功后,我们输出这两个传来的值到控制台。
注意:Javascript调用的OC函数,此函数返回值类型必须是void。由于React Native的桥接操作是异步的,所以要返回结果给Javascript,必须通过回调参数进行 后续详细讲解。
从js传来的参数我们可以依靠自动类型转换的特性,跳过手动的类型转换(RCTConvert,下面详细介绍),在定义函数参数类型时,直接写上对应想要的数据类型,例如NSData等。
5. 下面看js调用的代码段:
var TestOJO = require('react-native').NativeModules.TestOJO; TestOJO.j2oFun1('Himi', 12321);
var TestOJO=require(‘react-native’).NativeModules.TestOJO;(将OC注册进来的模块取出)
TestOJO.j2oFun1(‘Himi’, 12321);(调用模块中的对应函数,且将参数进行传入)
6. 我们来看一段复杂的数据通信
OC 代码段(导出函数):
#import "RCTConvert.h" RCT_EXPORT_METHOD(j2oFun2:(NSDictionary *)details) {NSString *name = [RCTConvert NSString:details[@"name"]];NSNumber *age = [RCTConvert NSNumber:details[@"age"]];NSArray * array =[RCTConvert NSArray:details[@"array"]];NSLog(@"js call iOS function j2oFun2\n name: %@ | age :%@", name, [age stringValue]);for (int i = 0; i<[array count]; i++) {NSLog(@"array: 第%d个元素:%@",i,array[i]);} }
需要注意的是,引入了”RCTConvert”类,作用:
RCTConvert提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。
JS代码段:(调用OC函数)
TestOJO.j2oFun2({name:'Himi',age:12,array:['hi,Himi','i,m','a array!']});
7. 我们下面来利用回调参数来得到访问OC的函数得到其返回值
RCT_EXPORT_METHOD(j2oCallbackEvent:(NSString *)jsString callback:(RCTResponseSenderBlock)callback) {NSLog(@"js call iOS function: j2oCallbackEvent \n jsString:%@",jsString);NSArray *events = [[NSArray alloc] initWithObjects:@"Himi",@"12321", nil];callback(@[[NSNull null], events]); }
RCTResponseSenderBlock 是种特殊的参数类型——回调函数,通过此参数可以实现当JS访问的OC函数后,并能将此OC函数的返回值传递给JS。
RCTResponseSenderBlock 只接受一个参数(传递给JavaScript回调函数的参数数组)
callback函数:第一个参数是一个错误对象(没有发生错误的时候为null),而剩下的部分是函数的返回值。
下面我们来看JS调用代码段:
TestOJO.j2oCallbackEvent('Himi',(error,callBackEvents)=>{if (error) {console.error(error);} else {Alert.alert('J2O带返回值', '数组的三个值:\n[0]:'+callBackEvents[0]+'\n[1]:'+callBackEvents[1]+'\n[2]:'+callBackEvents[2]);} });
二: iOS访问React Native
1. 我们如果想要OC访问JS,给JavaScript发送事件通知,我们需要使用RCTEventDispatcher的函数,与RCTBridge的实例
因此我们需要先做准备,TestOJO.h:
#import "RCTEventDispatcher.h" @synthesize bridge = _bridge;
bridge: 是RCTBridge 的实例,且在我们使用的接口 RCTBridgeModule中。
OC访问JS的代码段:
[self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:@{@"name":@"Himi",@"age": @12}];
第一个参数:事件名
第二个参数(body):传入的参数
其中@{}是定义不可变的字典的快捷实例方式,因此我们也可以改成如下形式:
NSDictionary * direct =@{@"name": @"Himi",@"age": @12};[self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:direct];
下面来看JS中定义OC调用的函数:
其实所谓OC能响应JS,是JS进行了对应函数的绑定监听。因此我们需要利用 NativeAppEventEmitter 组件,利用其addListener进行注册监听!因此我们需要引入进来这个模块,
import {...NativeAppEventEmitter...} from 'react-native'; var o2cFun = NativeAppEventEmitter.addListener('eventName',(para) => Alert.alert('被OC触发','字典数据:\n name:'+para.name+'\n age:'+para.age) );
var o2cFun : 将绑定好的监听事件引用交给此变量保存。
addListener:
第一个参数:事件名
第二个参数:响应函数
注意:利用addListener进行监听,一定要对应有取消监听!要保持一一对应的好习惯。
且通常取消监听都在componentWillUnmount函数中进行。如下:
componentWillUnmount(){o2cFun.remove();}
其中对于原理并没有详细的介绍,这里推荐两篇文章,童鞋们可以详细的阅读一下,这里不赘述:
http://www.jianshu.com/p/203b91a77174
http://reactnative.cn/docs/0.21/native-modules-ios.html#content
下面给出源码:
TestOJO.h:
// // TestOJO.h // MyProject // // Created by Himi on 16/6/2. // Copyright 2016年 Facebook. All rights reserved. // #import <Foundation/Foundation.h> #import "RCTBridgeModule.h" @interface TestOJO : NSObject <RCTBridgeModule> @end
TestOJO.m:
// // TestOJO.m // MyProject // // Created by Himi on 16/6/2. // Copyright 2016年 Facebook. All rights reserved. // #import "TestOJO.h" //RCTConvert类支持的的类型也都可以使用,RCTConvert还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。 #import "RCTConvert.h" //本地模块也可以给JavaScript发送事件通知。最直接的方式是使用eventDispatcher #import "RCTEventDispatcher.h" @implementation TestOJO //====================================[JS -> OC]======================================= RCT_EXPORT_MODULE(); //桥接到Javascript的方法返回值类型必须是void。React Native的桥接操作是异步的,所以要返回结果给Javascript,必须通过回调或者触发事件来进行 RCT_EXPORT_METHOD(j2oFun1:(NSString *)dataString dateNumber:(int)dateNumber) {NSLog(@"js call iOS function j2oFun1\n dataString: %@ |dateNumber :%d",dataString,dateNumber); } RCT_EXPORT_METHOD(j2oFun2:(NSDictionary *)details) {NSString *name = [RCTConvert NSString:details[@"name"]];NSNumber *age = [RCTConvert NSNumber:details[@"age"]];NSArray * array =[RCTConvert NSArray:details[@"array"]];NSLog(@"js call iOS function j2oFun2\n name: %@ | age :%@", name, [age stringValue]);for (int i = 0; i<[array count]; i++) {NSLog(@"array: 第%d个元素:%@",i,array[i]);}} //带回调函数 RCTResponseSenderBlock ,提供将返回值传回给js //RCTResponseSenderBlock 只接受一个参数->传递给JavaScript回调函数的参数数组 RCT_EXPORT_METHOD(j2oCallbackEvent:(NSString *)jsString callback:(RCTResponseSenderBlock)callback) {NSLog(@"js call iOS function: j2oCallbackEvent \n jsString:%@",jsString);NSArray *events = [[NSArray alloc] initWithObjects:@"Himi",@"12321", nil];callback(@[[NSNull null], events]); } //====================================[OC -> JS]======================================= @synthesize bridge = _bridge; //此函数是为了测试OC->JS过程,触发事件的函数 RCT_EXPORT_METHOD(emitterO2J) {[self ocCallJsFun]; } - (void)ocCallJsFun {NSDictionary * direct =@{@"name": @"Himi",@"age": @12};[self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:direct];// [self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:@{@"name":@"Himi",@"age": @12}];} @end
Main.js:
import React, { Component } from 'react'; import {View,Text,StyleSheet,Image,Alert,NativeAppEventEmitter,//引用NativeAppEventEmitter组件进行监听Native端派发的事件} from 'react-native'; var TestOJO = require('react-native').NativeModules.TestOJO; var o2cFun = NativeAppEventEmitter.addListener('eventName',(para) => Alert.alert('被OC触发','字典数据:\n name:'+para.name+'\n age:'+para.age) ); // 千万不要忘记忘记取消订阅, 通常在componentWillUnmount函数中实现。 // o2cFun.remove(); export default class Main extends Component {constructor(props) {super(props);this.state = {selectedTab:'home'};}componentWillUnmount(){o2cFun.remove();}render() {return (<View style={{flex: 1, alignItems: 'center'}}><Text style={styles.himiTextStyle}>Himi React Native 系列教程</Text><TextonPress={()=>{TestOJO.j2oFun1('Himi', 12321);TestOJO.j2oFun2({name:'Himi',age:12,array:['hi,Himi','i,m','a array!']});TestOJO.j2oCallbackEvent('Himi',(error,callBackEvents)=>{if (error) {console.error(error);} else {Alert.alert('J2O带返回值', '数组的三个值:\n[0]:'+callBackEvents[0]+'\n[1]:'+callBackEvents[1]+'\n[2]:'+callBackEvents[2]);}});}}style={styles.himiTextStyle}>JS -> OC</Text><TextonPress={()=>{TestOJO.emitterO2J();}}style={styles.himiTextStyle}>JS -> OC -> JS</Text></View>);} }; var styles = StyleSheet.create({himiTextStyle:{backgroundColor:'#eee',color:'#f00',fontSize:30,marginTop:70,}, });
下面是运行效果:(点击看动态图,主要看演示过程与控制台输出哦!)
注意:
1.点击JS->OC 后,会调用三个函数哦
2.点击JS->OC->JS, 先是通过JS->OC的临时函数,触发OC->JS的过程!
【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信相关推荐
- Java NIO系列教程(十二) Java NIO与IO
原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov 译者:郭蕾 校对:方腾飞 当学习了Java ...
- 推荐系统系列教程之十二:Facebook是怎么为十亿人互相推荐好友的?
编者按:之前推出了<推荐系统系列教程>,反响不错,前面已经推出了十一期,今天按约推出第十二期:Facebook是怎么为十亿人互相推荐好友的.希望朋友们多点"在看",多多 ...
- 架构思维成长系列教程(十二)- 云平台架构设计
背景 云平台是个非常宽泛的领域,一般分成:IaaS 基础设施即服务.PaaS 平台即服务.SaaS 软件即服务,本文侧重介绍企业私有云平台架构. 内容 云平台技术架构 云平台技术架构 如图所示,这是一 ...
- Linux (x86) Exploit 开发系列教程之十二 释放后使用
释放后使用 译者:飞龙 原文:Use-After-Free 预备条件: Off-By-One 漏洞(基于栈) 理解 glibc malloc VM 配置:Fedora 20(x86) 什么是释放后使用 ...
- WPF系列教程(十二):控件类——前景背景、字体Background、Foreground、FontFamily、FontSize
控件都包含背景画刷和前景画刷属性. 部分控件包含字体属性. 鼠标光标的设置. 示例项目源码 为控件设置背景与前景 下面这个窗体 <Window x:Class="Control.Mai ...
- Vue.js学习系列(四十二)-- Vue.js组件
2019独角兽企业重金招聘Python工程师标准>>> 组件(Component)是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.组件系统让我们可以用独立 ...
- 【REACT NATIVE 系列教程之十三】利用LISTVIEW与TEXTINPUT制作聊天/对话框获取组件实例常用的两种方式...
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2346.html ...
- React+Redux系列教程
2019独角兽企业重金招聘Python工程师标准>>> 参考项目:https://github.com/lewis617/react-redux-tutorial 参考项目下载地址: ...
- Linux Shell脚本入门教程系列之(十二)Shell until循环
本文是Linux Shell脚本系列教程的第(十二)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 在上两篇文章Linux Shell系列教程之(十)Shell for循环 ...
最新文章
- 人生快乐之道(组图)
- Shell until循环
- 好好学python·函数进阶(递归函数,回调函数,闭包函数,匿名函数,迭代器)
- @Autowired @Resource @Inject 自动注入
- ArcGIS实验教程——实验八:矢量数据拼接
- WePY:在质疑中前进 | 文末福利
- struts国际化java_Struts2 的国际化实现方式示例
- C#基础知识五之abstract virtual关键字
- 求三角形面积(C++)
- C#语法基础(三)----窗体设计
- linux zip压缩比1000,linux下压缩工具总结与使用(参考私房菜)
- 看拉扎维《模拟CMOS集成电路设计》的一些总结和思考(六)——放大器的频率特性
- 上海计算机一级excel试题及答案,2016年计算机一级excel试题及答案
- 安装历史版本nvidia显卡驱动
- Ubuntu 20.04 上安装使用 ibus-rime(超实用)
- 巴塞尔iii_巴塞尔协议——银行风控实施的超级系统工程 之二
- 再次携号转网_移动再次确认:这三个号段将不能携号转网!
- 关于Linux mint更换中文字体后全局楷体修改办法
- 2017南京理工大学计算机录取分数,2018南京理工大学录取分数线预估 2017录取分数线...
- 关于android 电池的一些实用性探讨