【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 ...
随机推荐
- vue+cordova项目
教你用Cordova打包Vue项目 现在国内越来越多的开发者使用Vue开发混合app,但是当大家开发完成过后才发现不知道该怎么将Vue项目打包成app.据我现在的了解打包Vue项目目前流行的就是使 ...
- Python学习之环境搭建及模块引用
这是我学习Python过程积累的经验和踩过的坑,希望学习Python的新手们能尽量避免,以免不必要的时间浪费.今天也是我第一次接触Python. 基础语法看了两个晚上,所以如果没看的朋友们,抽时间先看 ...
- 解决VS2010在新建实体数据模型出现“在 .NET Framework Data Provider for Microsoft SQL Server Compact 3.5 中发生错误。请与提供程序供应商联系以解决此问题。”的问题
最近想试着学习ASP.NET MVC,在点击 添加--新建项--Visual C#下的数据中的ADO.NET 实体数据模型,到"选择您的数据连接"时,出现错误,"在 .N ...
- The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the associated filter.
The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the assoc ...
- 把连接中传的参数截取出来变成一个json对象
获取url function test() { var url=window.location.search; if(url.indexOf("?")!=-1) { var str ...
- Java从入门到精通——数据库篇Mongo DB GridFS文件系统
一.概述 GridFS是MongoDB的一种存储机制,用来存储大型二进制文件. 优点: 1.使用GridFS能够简化你的栈.如果已经在使用MongoDB,那么可以使用GridFS来代替独立的文件 ...
- (C/C++) 用函数返回一个结构体
方法一: 参数里含有指向指针的指针. 注意:如果函数参数里只有一个指向结构体的指针,是无法正确地返回结构体的值的.原因在于在编译的时候,会对入参p产生一个备份_p. 参考此文:http://www.c ...
- Ubuntu / Raspberry 下切换GCC版本
目前Ubuntu 自带的GCC版本为4.6,遗憾的是在实际使用时,反而版本越高越好问题越多,所以,一旦遇到编译问题时最好先检查你下载的工程里的readme,默认的编译器版本是否为当前的安装版本,如果不 ...
- Python爬虫教程-22-lxml-etree和xpath配合使用
Python爬虫教程-22-lxml-etree和xpath配合使用 lxml:python 的HTML/XML的解析器 官网文档:https://lxml.de/ 使用前,需要安装安 lxml 包 ...
- tensorflow: a Implementation of rotation ops (旋转的函数实现方法)
tensorflow 旋转矩阵的函数实现方法 关键字: rot90, tensorflow 1. 背景 在做数据增强的操作过程中, 很多情况需要对图像旋转和平移等操作, 针对一些特殊的卷积(garbo ...