【React Native开发】React Native 进阶之原生混合与数据通信开发详解-适配iOS开发(61)

前端之家收集整理的这篇文章主要介绍了【React Native开发】React Native 进阶之原生混合与数据通信开发详解-适配iOS开发(61)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

【React Native开发】React Native 进阶之原生混合与数据通信开发详解-适配iOS开发(61)

尊重版权,未经授权不得转载

本文来自:江清清的技术专栏(http://www.lcode.org)

(一)前言

今天我们来看一下React Native iOS开发中,React界面和原生iOS混合开发以及数据相互传输详解。

刚创建的React Native交流6群:426762904,欢迎各位大牛,React Native技术爱好者加入交流!同时博客右侧欢迎微信扫描关注订阅号,移动技术干货,精彩文章技术推送!

[特别提醒].在看本文章之前,首先确定自己已经学过我的博客另外两节内容了:

1.1.React Native进阶之原生模块封装基础篇详解-适配iOS开发

1.2.React Native进阶之原生模块封装特性篇详解-适配iOS开发

从现阶段RN的发展程度来看,RN和原生混合开发模式是比较理想的,所以我们非常有必要讲解一下RN和原生混合的开发模式,同时里边有关的数据交互通信知识点也有必要讲解一下啦。那么现在我们来一起看一下该怎么样去实现。本篇主要会讲解如下几部分内容:①.React Native访问调用iOS方法,②.iOS访问调用React Native,③.原生界面跳转RN界面。本文章讲解是是适配iOS平台开发的,如果你需要看Android部分的请移步:http://www.lcode.org/?p=1689

文章实例项目地址:https://github.com/jiangqqlmj/hunheDemo

(二).原生界面跳转RN界面

现阶段混合开发中,一般就是在原有原生项目基础上面添加RN开发的页面。那么这边我们讲解一下从原生界面跳转到RN页面方法。其实是非常简单的,就是普通push一个ViewController即可,在新打开的ViewController中加入RCTRootView视图,具体承载RN页面的控制器的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# import "TwoViewController.h"
"RCTRootView.h"
"ThreeViewController.h"
@implementation TwoViewController
- ( void )viewDidLoad {
[ super viewDidLoad];
@H_502_140@self.title=@ "RN界面" ;
@H_502_140@NSURL *jsCodeLocation=[NSURL URLWithString:@ "http://localhost:8081/index.ios.bundle?platform=ios&dev=true" ];
@H_502_140@RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
@H_502_140@moduleName:@ "hunheDemo"
@H_502_140@initialProperties:nil
@H_502_140@launchOptions:nil];
@H_502_140@self.view=rootView;
}
@end
(三).React Native访问调用iOS原生方法

要实现这个功能,我们首先需用创建一个实现"RCTBridgeModule"协议的RNBridgeModule桥接类,看一下RNBridgeModule.h文件

5
import <Foundation/Foundation.h>
"RCTBridgeModule.h"
@interface RNBridgeModule : NSObject<RCTBridgeModule>
@end

接着我们需要在RNBridgetModule的实现类中,实现RCT_EXPORT_MODULE()宏定义,括号参数不填为默认桥接类的名称,也可以自定义填写。该名称用来指定在JavaScript中访问这个模块的名称

3.1.使用Callback进行回调

接下来我们在RNBridgeModule.m文件添加如下的方法:

6
//RN传参数调用原生OC,并且返回数据给RN 通过CallBack
RCT_EXPORT_METHOD(RNInvokeOCCallBack:(NSDictionary *)dictionary callback:(RCTResponseSenderBlock)callback){
@H_502_140@NSLog(@ "接收到RN传过来的数据为:%@" ,dictionary);
@H_502_140@NSArray *events = [[NSArray alloc] initWithObjects:@ "张三" "李四" @H_502_140@callback(@[[NSNull null ],events]);
}

根据之前的文章讲过,如果原生的方法要被JavaScript进行访问,那么该方法需要使用RCT_EXPORT_METHOD()宏定义进行声明。该声明的RNInvokeOCCallBack方法有两个参数:第一个参数代表从JavaScript传过来的数据,第二个参数是回调方法,通过该回调方法把原生信息发送到JavaScript中。其中上面的callback方法中传入一个参数数组,其实该数组的第一个参数为一个NSError对象,如果没有错误返回null,其余的数据作为该方法的返回值回调给JavaScritp。

最后我们需要在JavaScript文件中进行定义导出在原生封装的模块,然后调用封装方法访问即可:

14
var { NativeModules } = require( 'react-native' );
var RNBridgeModule=NativeModules.RNBridgeModule;
RNBridgeModule.RNInvokeOCCallBack(
@H_502_140@{ 'name' : 'jiangqq' 'description' 'http://www.lcode.org' },
@H_502_140@(error,events)=>{
if (error){
@H_502_140@console.error(error);
@H_502_140@} else {
this .setState({events:events});
@H_502_140@}
@H_502_140@}
@H_502_140@)
3.2.使用Promise进行回调

上面讲解过了JavaScript调用iOS原生方法,但是数据回调是通过Callback的,这边我在讲解一下使用Promise进行回调的方法。来我们在

RNBridgetModule的实现类添加如下的方法代码:

12
RCT_EXPORT_METHOD(RNInvokeOCPromise:(NSDictionary *)dictionary resolver:(RCTPromiseResolveBlock)resolve
@H_502_140@rejecter:(RCTPromiseRejectBlock)reject){
@H_502_140@NSString *value=[dictionary objectForKey:@ "name" ];
@H_502_140@([value isEqualToString:@ "jiangqq" ]){
@H_502_140@resolve(@ "回调成功啦,Promise..." );
@H_502_140@{
@H_502_140@NSError *error=[NSError errorWithDomain:@ "传入的name不符合要求,回调失败啦,255)!important; border:0px!important; bottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; margin:0px!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; min-height:auto!important"> code: 100 userInfo:nil];
@H_502_140@reject(@ "100" @H_502_140@}
这边定义了RNInvokeOCPromise方法,该会有三个参数:

  • dictionary:JavaScript传入的数据
  • resolve:成功,回调数据
  • reject:失败,回调数据

其中resove方法传入具体的成功信息即可,但是reject方法必须传入三个参数分别为,错误代码code,错误信息message以及NSError对象。最终看一下JavaScript中的调用方式:

var RNBridgeModule=NativeModules.RNBridgeModule;
//获取Promise对象处理
@H_502_140@async _updateEvents(){
try {
@H_502_140@var events=await RNBridgeModule.RNInvokeOCPromise({ 'jiangqqlmj' });
@H_502_140@.setState({events});
catch (e){
@H_502_140@.setState({events:e.message});
@H_502_140@}
(四).iOS原生访问调用React Native

如果我们需要从iOS原生方法发送数据到JavaScript中,那么可以使用eventDispatcher。首先我们需要在RCTBridgeModule实现中中引入:

3
"RCTBridge.h"
"RCTEventDispatcher.h"
@synthesize bridge = _bridge;

接下来通过iOS OC原生代码进行访问JavaScript了

1
self.bridge.eventDispatcher sendAppEventWithName:@ "EventReminder" body:@{@ :[NSString stringWithFormat:@ "%@" "errorCode" :@ "0" "msg" "成功" }];

看上面的sendAppEventWithName方法包含二个参数:

下面来看一下该调用方法的具体代码:

9
//OC调用RN
RCT_EXPORT_METHOD(VCOpenRN:(NSDictionary *)dictionary){
@H_502_140@];
@H_502_140@]){
@H_502_140@[self.bridge.eventDispatcher sendAppEventWithName:@ }];
"输入的name不是jiangqq" }];
@H_502_140@}
最后在JavaScript端进行调用方法如下:

15
16
17
18
19
20
{ NativeAppEventEmitter } from ;
componentDidMount(){
@H_502_140@console.log( '开始订阅通知...' );
@H_502_140@subscription = NativeAppEventEmitter.addListener(
'EventReminder' @H_502_140@(reminder) => {
@H_502_140@let errorCode=reminder.errorCode;
@H_502_140@(errorCode=== 0 ){
@H_502_140@.setState({msg:reminder.name});
@H_502_140@{
@H_502_140@.setState({msg:reminder.msg});
@H_502_140@}
@H_502_140@}
@H_502_140@);
@H_502_140@}
@H_502_140@componentWillUnmount(){
@H_502_140@subscription.remove();
如上的代码,首先通过导入NativeAppEventEmitter模块,使用该模块在JavaScript代码中进行注册订阅相应的事件。然后我们在生命周期方法componentDidMount()方法中使用addListener()方法进行添加订阅事件。有订阅当然有取消订阅,所以我们在componentWillUnmount()方法中使用remove()方法进行取消即可。

(五).实战实例

上面我们已经把JavaScript和iOS原生代码的相互访问调用以及原生界面打开RN界面都初步的讲解了一遍,下面我们来通过具体实例来演示一下效果(这边也只是贴出来主要代码,详细代码大家可以移步:https://github.com/jiangqqlmj/hunheDemo):

5.1.原生封装模块RCTBridgeModule.m代码

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
//
// RNBridgeModule.m
// hunheDemo
//
// Created by 江清清 on 16/6/5.
// Copyright © 2016年 Facebook. All rights reserved.
//
"RNBridgeModule.h"
"RCTBridge.h"
"RCTEventDispatcher.h"
RNBridgeModule
bridge = _bridge;
RCT_EXPORT_MODULE(RNBridgeModule)
RCT_EXPORT_METHOD(RNInvokeOCCallBack:(NSDictionary *)dictionary callback:(RCTResponseSenderBlock)callback){
}
RCT_EXPORT_METHOD(RNInvokeOCPromise:(NSDictionary *)dictionary resolver:(RCTPromiseResolveBlock)resolve
@H_502_140@rejecter:(RCTPromiseRejectBlock)reject){
@H_502_140@];
@H_502_140@]){
@H_502_140@);
@H_502_140@{
@H_502_140@ userInfo:nil];
@H_502_140@}
}
//RN跳转原生界面
//RCT_EXPORT_METHOD(RNOpenVC:(NSString *)msg){
// NSLog(@"RN传入原生界面的数据为:%@",msg);
// [[NSNotificationCenter defaultCenter]postNotificationName:@"RNOpenVC" object:nil];
//}
//OC调用RN
RCT_EXPORT_METHOD(VCOpenRN:(NSDictionary *)dictionary){
@H_502_140@];
@H_502_140@]){
@H_502_140@}];
@H_502_140@{
@H_502_140@}];
@H_502_140@}
}
5.2.前端index.ios.js代码如下:

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* Sample React Native App
* @flow
*/
import React,{ Component } from 'react' ;
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native' ;
var { NativeModules } = require( );
RNBridgeModule=NativeModules.RNBridgeModule;
import { NativeAppEventEmitter } from ;
subscription; //订阅
class CustomButton extends Component {
render() {
return (
<TouchableHighlight
style={styles.button}
underlayColor= "#a5a5a5"
onPress={ this .props.onPress}>
<Text style={styles.buttonText}>{ .props.text}</Text>
</TouchableHighlight>
);
}
}
class hunheDemo extends Component {
constructor(props){
super (props);
.state={
events: '' msg: }
}
//获取Promise对象处理
async _updateEvents(){
try {
events=await RNBridgeModule.RNInvokeOCPromise({ 'name' : 'jiangqqlmj' });
.setState({events});
} catch (e){
.setState({events:e.message});
}
}
componentDidMount(){
console.log( '开始订阅通知...' );
subscription = NativeAppEventEmitter.addListener(
'EventReminder' (reminder) => {
let errorCode=reminder.errorCode;
if (errorCode===0){
.setState({msg:reminder.name});
else {
.setState({msg:reminder.msg});
}
}
);
}
componentWillUnmount(){
subscription.remove();
}
render() {
(
<View style={{marginTop:20}}>
<Text style={styles.welcome}>
混合与RN,iOS通信实例讲解
</Text>
<Text style={{margin:20}}>
来自:江清清的技术专栏(http: //www.lcode.org)
</Text>
<Text style={{margin:5}}> '返回数据为:' +{ .state.events}</Text>
<CustomButton text= 'RN调用iOS原生方法_CallBack回调'
onPress={()=>{RNBridgeModule.RNInvokeOCCallBack(
{ 'jiangqq' 'description' 'http://www.lcode.org' (error){
console.error(error);
{
.setState({events:events});
}
})}}
/>
'RN调用iOS原生方法_Promise回调'
onPress={()=> ._updateEvents()}
/>
<Text style={{margin:20}}>
.state.msg}
</Text>
'iOS调用访问React Native'
onPress={()=>RNBridgeModule.VCOpenRN({ })}
/>
</View>
);
}
}
const styles = StyleSheet.create({
welcome: {
fontSize: 20,
textAlign: 'center' margin: 10,
button: {
margin:5,
backgroundColor: 'white' padding: 10,
borderWidth: 1,
borderColor: '#facece' });
AppRegistry.registerComponent( 'hunheDemo' 5.3.运行效果

(六)最后总结

今天我们主要学习一下React Native iOS开发中,RN和原生iOS混合开发以及数据相互传输详解。

文章实例项目地址:https://github.com/jiangqqlmj/hunheDemo

尊重原创,未经授权不得转载:From Sky丶清(http://www.lcode.org/) 侵权必究!

关注我的订阅号(codedev123),每天分享移动开发技术(Android/IOS),项目管理以及博客文章!(欢迎关注,第一时间推送精彩文章)

关注我的微博,可以获得更多精彩内容

原文链接:https://www.f2er.com/react/304784.html

猜你在找的React相关文章