【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信
http://blog.csdn.net/xiaominghimi/article/details/51586492
一用到跨平台的引擎必然要有引擎与各平台原生进行交互通信的需要。那么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
1
2
3
4
5
6
|
#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中添加如下:
1
2
3
4
5
6
7
|
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调用的代码段:
1
2
3
|
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 代码段(导出函数):
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#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函数)
1
2
3
4
5
6
7
|
TestOJO.j2oFun2({
name:'Himi',
age:12,
array:[
'hi,Himi','i,m','a array!'
]
});
|
7. 我们下面来利用回调参数来得到访问OC的函数得到其返回值
1
2
3
4
5
6
|
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调用代码段:
1
2
3
4
5
6
7
|
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:
1
2
3
|
#import "RCTEventDispatcher.h"
@synthesize bridge = _bridge;
|
bridge: 是RCTBridge 的实例,且在我们使用的接口 RCTBridgeModule中。
OC访问JS的代码段:
1
|
[self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:@{@"name":@"Himi",@"age": @12}];
|
第一个参数:事件名
第二个参数(body):传入的参数
其中@{}是定义不可变的字典的快捷实例方式,因此我们也可以改成如下形式:
1
2
|
NSDictionary * direct =@{@"name": @"Himi",@"age": @12};
[self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:direct];
|
下面来看JS中定义OC调用的函数:
其实所谓OC能响应JS,是JS进行了对应函数的绑定监听。因此我们需要利用 NativeAppEventEmitter 组件,利用其addListener进行注册监听!因此我们需要引入进来这个模块,
1
2
3
4
5
6
7
8
9
10
|
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函数中进行。如下:
1
2
3
|
componentWillUnmount(){
o2cFun.remove();
}
|
其中对于原理并没有详细的介绍,这里推荐两篇文章,童鞋们可以详细的阅读一下,这里不赘述:
http://www.jianshu.com/p/203b91a77174
http://reactnative.cn/docs/0.21/native-modules-ios.html#content
下面给出源码:
TestOJO.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//
// 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
//
// 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
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>
<Text
onPress={()=>{
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>
<Text
onPress={()=>{
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 后,会调用三个函数哦
【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信的更多相关文章
- 数据挖掘入门系列教程(十二)之使用keras构建CNN网络识别CIFAR10
简介 在上一篇博客:数据挖掘入门系列教程(十一点五)之CNN网络介绍中,介绍了CNN的工作原理和工作流程,在这一篇博客,将具体的使用代码来说明如何使用keras构建一个CNN网络来对CIFAR-10数 ...
- guitar pro系列教程(十二):如何设置Guitar Pro的不完全小节
当我们新建一个GTP谱的时候,我们肯定是要用到节拍,是的,一个乐谱节拍设置的好不好,将直接影响你的乐谱效果好不好,设置节拍的步骤我们之前也有讨论过,今天主要跟大家讲的便是不完全小节. 不完全小节顾名思 ...
- Linux系列教程(十二)——Linux软件包管理之yum在线管理
上一篇博客我们介绍了rpm包管理之rpm命令管理,我们发现在使用rpm命令手动安装rpm包的时候,会发现安装遇到到的依赖让你痛不欲生,安装一个rpm时会要先先安装某个依赖的rpm,而安装这个依赖的rp ...
- Java NIO系列教程(十二) Java NIO与IO
当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...
- Spring Boot2 系列教程(三十二)Spring Boot 整合 Shiro
在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 Shiro. 今天松哥就来和大家聊聊 Spring Boot ...
- FL studio系列教程(十二):FL Studio中如何导出音频
在FL Studio中制作好音乐后,最后展现给我们的是一般的音频文件,我们可以通过FL Studio的文件菜单导出最终的文件格式.下面我们就来详细的看一下FL Studio中是如何导出我们想要的音频格 ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明
紧接上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明>,这里专讲OAuth2.0. 理解OAuth2.0 首先我们通过一张图片来了解一下OAu ...
- 【OpenCV新手教程之十二】OpenCV边缘检測:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/25560901 作者:毛星云(浅墨) ...
- [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...
随机推荐
- 用jQuery来绑定事件的3种方法和区别
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- sql语句将数字转为汉字展示
select [表字段Name] , ( case [表字段OrderState] when 1 then '已核销' when 2 then '确认前的移动端取消'when 3 then '已完成' ...
- CXF - 拦截器获取调用方法
没想到要弄这么一个东西. 起初只是想用interceptor记录一下webservice调用日志,后来却被要求在页面展示. 展示容易,但只是展示webservice的地址无法让用户从中明白什么. 那么 ...
- mysql Backup &recovery
备份数据库非常重要,这样您就可以恢复数据,并在发生问题时重新启动并运行,例如系统崩溃,硬件故障或用户错误地删除数据. 在升级MySQL安装之前,备份也是必不可少的保护措施,它们可用于将MySQL安装转 ...
- 一、python简单爬取静态网页
一.简单爬虫框架 简单爬虫框架由四个部分组成:URL管理器.网页下载器.网页解析器.调度器,还有应用这一部分,应用主要是NLP配合相关业务. 它的基本逻辑是这样的:给定一个要访问的URL,获取这个ht ...
- 来看看javaweb的自定义标签
1.为什么需要自定义标签? jsp的简单标签其实就是jsp的自定义标签,主要作用就是移除jsp页面中的java代码,使得jsp页面只有标签和EL表达式,而没有java代码.利用自定义标签,可以使软件开 ...
- docker 容器中设置 mysql lampp php软链接
在容器中安装xampp后,进入到终端,直接输入mysql php 发现报错,命令未被发现.如果输入/opt/lampp/bin/mysql 就可以进入了,所以我们要找到在容器中安装的位置,然后将他 ...
- JS原型链继承
继承普通版 继承逻辑上都差不多,普通版调用方式比较繁琐,不利于反复大量的使用: (function (){ //创建一个人员类 function Person(name){ this.name = n ...
- Java BeanUtils 组件 使用
1. BeanUtils组件 1.1 简介 程序中对javabean的操作很频繁, 所以apache提供了一套开源的api,方便对javabean的操作!即BeanUtils组件. BeanUtils ...
- [小北De编程手记] : Lesson 04 - Selenium For C# 之 API 上
这一部分,我准备向大家介绍Selenium WebDriver的常用API,学习这部分内容需要大家最好有一些简单的HTML相关知识,本文主要涉及到以下内容: Selenium API:元素检查 Sel ...