【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

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
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
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
#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
#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
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
//
//  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
//
//  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
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,
   },
});

下面是运行效果:(点击看动态图,主要看演示过程与控制台输出哦!)

user918

注意:

1.点击JS->OC 后,会调用三个函数哦

2.点击JS->OC->JS, 先是通过JS->OC的临时函数,触发OC->JS的过程!





本文转自 xiaominghimi 51CTO博客,原文链接:http://blog.51cto.com/xiaominghimi/1786162,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
前端开发 JavaScript NoSQL
使用 Node.js、Express 和 React 构建强大的 API
本文详细介绍如何使用 Node.js、Express 和 React 构建强大且动态的 API。从开发环境搭建到集成 React 前端,再到利用 APIPost 高效测试 API,适合各水平开发者。内容涵盖 Node.js 运行时、Express 框架与 React 库的基础知识及协同工作方式,还涉及数据库连接和前后端数据交互。通过实际代码示例,助你快速上手并优化应用性能。
|
8月前
|
前端开发 JavaScript 测试技术
React 中集成 Chart.js 图表库
本文介绍了如何在 React 项目中集成 Chart.js 创建动态图表,涵盖基础概念、安装步骤、代码示例及常见问题解决方法,帮助开发者轻松实现数据可视化。
214 11
|
8月前
|
监控 前端开发 JavaScript
React 静态网站生成工具 Next.js 入门指南
【10月更文挑战第20天】Next.js 是一个基于 React 的服务器端渲染框架,由 Vercel 开发。本文从基础概念出发,逐步探讨 Next.js 的常见问题、易错点及解决方法,并通过具体代码示例进行说明,帮助开发者快速构建高性能的 Web 应用。
343 11
|
8月前
|
资源调度 前端开发 数据可视化
构建高效的数据可视化仪表板:D3.js与React的融合之道
【10月更文挑战第25天】在数据驱动的时代,将复杂的数据集转换为直观、互动式的可视化表示已成为一项至关重要的技能。本文深入探讨了如何结合D3.js的强大可视化功能和React框架的响应式特性来构建高效、动态的数据可视化仪表板。文章首先介绍了D3.js和React的基础知识,然后通过一个实际的项目案例,详细阐述了如何将两者结合使用,并提供了实用的代码示例。无论你是数据科学家、前端开发者还是可视化爱好者,这篇文章都将为你提供宝贵的洞见和实用技能。
236 5
|
9月前
|
前端开发 JavaScript CDN
React 教程
10月更文挑战第6天
112 3
|
10月前
|
Web App开发 前端开发 测试技术
react18基础教程系列--安装环境及packagejson文件分析
react18基础教程系列--安装环境及packagejson文件分析
|
9月前
|
开发框架 前端开发 JavaScript
React、Vue.js 和 Angular主流前端框架和选择指南
在当今的前端开发领域,选择合适的框架对于项目的成功至关重要。本文将介绍几个主流的前端框架——React、Vue.js 和 Angular,探讨它们各自的特点、开发场景、优缺点,并提供选择框架的建议。
207 6
|
10月前
|
前端开发 JavaScript 开发者
React 和 Vue.js 框架的区别是什么?
React 和 Vue.js 框架的区别是什么?
|
11月前
|
JSON 前端开发 JavaScript
|
10月前
|
前端开发 JavaScript API
React、Vue.js 和 Angular前端三大框架对比与选择
前端框架是用于构建用户界面的工具和库,它提供组件化结构、数据绑定、路由管理和状态管理等功能,帮助开发者高效地创建和维护 web 应用的前端部分。常见的前端框架如 React、Vue.js 和 Angular,能够提高开发效率并促进团队协作。
455 4

热门文章

最新文章