【React Native开发】React Native 进阶之原生混合与数据通信开发详解-适配iOS开发(61)
来源:互联网 发布:java设计模式 百度云 编辑:程序博客网 时间:2024/06/07 04:59
【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页面的控制器的代码如下:
#
import
"TwoViewController.h"
#
import
"RCTRootView.h"
#
import
"ThreeViewController.h"
@implementation
TwoViewController
- (
void
)viewDidLoad {
[
super
viewDidLoad];
self.title=@
"RN界面"
;
NSURL *jsCodeLocation=[NSURL URLWithString:@
"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"
];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@
"hunheDemo"
initialProperties:nil
launchOptions:nil];
self.view=rootView;
}
@end
(三).React Native访问调用iOS原生方法
要实现这个功能,我们首先需用创建一个实现"RCTBridgeModule"协议的RNBridgeModule桥接类,看一下RNBridgeModule.h文件
#
import
<Foundation/Foundation.h>
#
import
"RCTBridgeModule.h"
@interface
RNBridgeModule : NSObject<RCTBridgeModule>
@end
接着我们需要在RNBridgetModule的实现类中,实现RCT_EXPORT_MODULE()宏定义,括号参数不填为默认桥接类的名称,也可以自定义填写。该名称用来指定在JavaScript中访问这个模块的名称。
3.1.使用Callback进行回调
接下来我们在RNBridgeModule.m文件中添加如下的方法:
//RN传参数调用原生OC,并且返回数据给RN 通过CallBack
RCT_EXPORT_METHOD(RNInvokeOCCallBack:(NSDictionary *)dictionary callback:(RCTResponseSenderBlock)callback){
NSLog(@
"接收到RN传过来的数据为:%@"
,dictionary);
NSArray *events = [[NSArray alloc] initWithObjects:@
"张三"
,@
"李四"
, nil];
callback(@[[NSNull
null
], events]);
}
根据之前的文章讲过,如果原生的方法要被JavaScript进行访问,那么该方法需要使用RCT_EXPORT_METHOD()宏定义进行声明。该声明的RNInvokeOCCallBack方法有两个参数:第一个参数代表从JavaScript传过来的数据,第二个参数是回调方法,通过该回调方法把原生信息发送到JavaScript中。其中上面的callback方法中传入一个参数数组,其实该数组的第一个参数为一个NSError对象,如果没有错误返回null,其余的数据作为该方法的返回值回调给JavaScritp。
最后我们需要在JavaScript文件中进行定义导出在原生封装的模块,然后调用封装方法访问即可:
var { NativeModules } = require(
'react-native'
);
var RNBridgeModule=NativeModules.RNBridgeModule;
RNBridgeModule.RNInvokeOCCallBack(
{
'name'
:
'jiangqq'
,
'description'
:
'http://www.lcode.org'
},
(error,events)=>{
if
(error){
console.error(error);
}
else
{
this
.setState({events:events});
}
}
)
}
3.2.使用Promise进行回调
上面讲解过了JavaScript调用iOS原生方法,但是数据回调是通过Callback的,这边我在讲解一下使用Promise进行回调的方法。来我们在
RNBridgetModule的实现类添加如下的方法代码:
//RN传参数调用原生OC,并且返回数据给RN 通过Promise
RCT_EXPORT_METHOD(RNInvokeOCPromise:(NSDictionary *)dictionary resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject){
NSLog(@
"接收到RN传过来的数据为:%@"
,dictionary);
NSString *value=[dictionary objectForKey:@
"name"
];
if
([value isEqualToString:@
"jiangqq"
]){
resolve(@
"回调成功啦,Promise..."
);
}
else
{
NSError *error=[NSError errorWithDomain:@
"传入的name不符合要求,回调失败啦,Promise..."
code:
100
userInfo:nil];
reject(@
"100"
,@
"传入的name不符合要求,回调失败啦,Promise..."
,error);
}
}
这边定义了RNInvokeOCPromise方法,该会有三个参数:
- dictionary:JavaScript传入的数据
- resolve:成功,回调数据
- reject:失败,回调数据
其中resove方法传入具体的成功信息即可,但是reject方法必须传入三个参数分别为,错误代码code ,错误信息message以及NSError对象。最终看一下JavaScript中的调用方式:
var { NativeModules } = require(
'react-native'
);
var RNBridgeModule=NativeModules.RNBridgeModule;
//获取Promise对象处理
async _updateEvents(){
try
{
var events=await RNBridgeModule.RNInvokeOCPromise({
'name'
:
'jiangqqlmj'
});
this
.setState({events});
}
catch
(e){
this
.setState({events:e.message});
}
}
(四).iOS原生访问调用React Native
如果我们需要从iOS原生方法发送数据到JavaScript中,那么可以使用eventDispatcher。首先我们需要在RCTBridgeModule实现中中引入:
#
import
"RCTBridge.h"
#
import
"RCTEventDispatcher.h"
@synthesize
bridge = _bridge;
接下来通过iOS OC原生代码进行访问JavaScript了
self.bridge.eventDispatcher sendAppEventWithName:@
"EventReminder"
body:@{@
"name"
:[NSString stringWithFormat:@
"%@"
,value],@
"errorCode"
:@
"0"
,@
"msg"
:@
"成功"
}];
看上面的sendAppEventWithName方法包含二个参数:
- 第一个参数:EventReminder自定义一个事件名称
- 第二个参数:具体传入JavaScrtipt的数据信息
下面来看一下该调用的方法的具体代码:
//OC调用RN
RCT_EXPORT_METHOD(VCOpenRN:(NSDictionary *)dictionary){
NSString *value=[dictionary objectForKey:@
"name"
];
if
([value isEqualToString:@
"jiangqq"
]){
[self.bridge.eventDispatcher sendAppEventWithName:@
"EventReminder"
body:@{@
"name"
:[NSString stringWithFormat:@
"%@"
,value],@
"errorCode"
:@
"0"
,@
"msg"
:@
"成功"
}];
}
else
{
[self.bridge.eventDispatcher sendAppEventWithName:@
"EventReminder"
body:@{@
"name"
:[NSString stringWithFormat:@
"%@"
,value],@
"errorCode"
:@
"0"
,@
"msg"
:@
"输入的name不是jiangqq"
}];
}
}
最后在JavaScript端进行调用的方法如下:
import
{ NativeAppEventEmitter } from
'react-native'
;
componentDidMount(){
console.log(
'开始订阅通知...'
);
subscription = NativeAppEventEmitter.addListener(
'EventReminder'
,
(reminder) => {
let errorCode=reminder.errorCode;
if
(errorCode===
0
){
this
.setState({msg:reminder.name});
}
else
{
this
.setState({msg:reminder.msg});
}
}
);
}
componentWillUnmount(){
subscription.remove();
}
如上的代码,首先通过导入NativeAppEventEmitter模块,使用该模块在JavaScript代码中进行注册订阅相应的事件。然后我们在生命周期方法componentDidMount()方法中使用addListener()方法进行添加订阅事件。有订阅当然有取消订阅,所以我们在componentWillUnmount()方法中使用remove()方法进行取消即可。
(五).实战实例
上面我们已经把JavaScript和iOS原生代码的相互访问调用以及原生界面打开RN界面都初步的讲解了一遍,下面我们来通过具体实例来演示一下效果(这边也只是贴出来主要代码,详细代码大家可以移步:https://github.com/jiangqqlmj/hunheDemo):
5.1.原生封装模块RCTBridgeModule.m代码
//
// RNBridgeModule.m
// hunheDemo
//
// Created by 江清清 on 16/6/5.
// Copyright © 2016年 Facebook. All rights reserved.
//
#
import
"RNBridgeModule.h"
#
import
"RCTBridge.h"
#
import
"RCTEventDispatcher.h"
@implementation
RNBridgeModule
@synthesize
bridge = _bridge;
RCT_EXPORT_MODULE(RNBridgeModule)
//RN传参数调用原生OC,并且返回数据给RN 通过CallBack
RCT_EXPORT_METHOD(RNInvokeOCCallBack:(NSDictionary *)dictionary callback:(RCTResponseSenderBlock)callback){
NSLog(@
"接收到RN传过来的数据为:%@"
,dictionary);
NSArray *events = [[NSArray alloc] initWithObjects:@
"张三"
,@
"李四"
, nil];
callback(@[[NSNull
null
], events]);
}
//RN传参数调用原生OC,并且返回数据给RN 通过Promise
RCT_EXPORT_METHOD(RNInvokeOCPromise:(NSDictionary *)dictionary resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject){
NSLog(@
"接收到RN传过来的数据为:%@"
,dictionary);
NSString *value=[dictionary objectForKey:@
"name"
];
if
([value isEqualToString:@
"jiangqq"
]){
resolve(@
"回调成功啦,Promise..."
);
}
else
{
NSError *error=[NSError errorWithDomain:@
"传入的name不符合要求,回调失败啦,Promise..."
code:
100
userInfo:nil];
reject(@
"100"
,@
"传入的name不符合要求,回调失败啦,Promise..."
,error);
}
}
//RN跳转原生界面
//RCT_EXPORT_METHOD(RNOpenVC:(NSString *)msg){
// NSLog(@"RN传入原生界面的数据为:%@",msg);
// [[NSNotificationCenter defaultCenter]postNotificationName:@"RNOpenVC" object:nil];
//}
//OC调用RN
RCT_EXPORT_METHOD(VCOpenRN:(NSDictionary *)dictionary){
NSString *value=[dictionary objectForKey:@
"name"
];
if
([value isEqualToString:@
"jiangqq"
]){
[self.bridge.eventDispatcher sendAppEventWithName:@
"EventReminder"
body:@{@
"name"
:[NSString stringWithFormat:@
"%@"
,value],@
"errorCode"
:@
"0"
,@
"msg"
:@
"成功"
}];
}
else
{
[self.bridge.eventDispatcher sendAppEventWithName:@
"EventReminder"
body:@{@
"name"
:[NSString stringWithFormat:@
"%@"
,value],@
"errorCode"
:@
"0"
,@
"msg"
:@
"输入的name不是jiangqq"
}];
}
}
@end
5.2.前端index.ios.js代码如下:
/**
* Sample React Native App
*https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from
'react'
;
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight
} from
'react-native'
;
var
{ NativeModules } = require(
'react-native'
);
var
RNBridgeModule=NativeModules.RNBridgeModule;
import { NativeAppEventEmitter } from
'react-native'
;
var
subscription;
//订阅者
class CustomButton extends Component {
render() {
return
(
<TouchableHighlight
style={styles.button}
underlayColor=
"#a5a5a5"
onPress={
this
.props.onPress}>
<Text style={styles.buttonText}>{
this
.props.text}</Text>
</TouchableHighlight>
);
}
}
class hunheDemo extends Component {
constructor(props){
super
(props);
this
.state={
events:
''
,
msg:
''
,
}
}
//获取Promise对象处理
async _updateEvents(){
try
{
var
events=await RNBridgeModule.RNInvokeOCPromise({
'name'
:
'jiangqqlmj'
});
this
.setState({events});
}
catch
(e){
this
.setState({events:e.message});
}
}
componentDidMount(){
console.log(
'开始订阅通知...'
);
subscription = NativeAppEventEmitter.addListener(
'EventReminder'
,
(reminder) => {
let errorCode=reminder.errorCode;
if
(errorCode===0){
this
.setState({msg:reminder.name});
}
else
{
this
.setState({msg:reminder.msg});
}
}
);
}
componentWillUnmount(){
subscription.remove();
}
render() {
return
(
<View style={{marginTop:20}}>
<Text style={styles.welcome}>
混合与RN,iOS通信实例讲解
</Text>
<Text style={{margin:20}}>
来自:江清清的技术专栏(http:
//www.lcode.org)
</Text>
<Text style={{margin:5}}>
'返回数据为:'
+{
this
.state.events}</Text>
<CustomButton text=
'RN调用iOS原生方法_CallBack回调'
onPress={()=>{RNBridgeModule.RNInvokeOCCallBack(
{
'name'
:
'jiangqq'
,
'description'
:
'http://www.lcode.org'
},
(error,events)=>{
if
(error){
console.error(error);
}
else
{
this
.setState({events:events});
}
})}}
/>
<CustomButton text=
'RN调用iOS原生方法_Promise回调'
onPress={()=>
this
._updateEvents()}
/>
<Text style={{margin:20}}>
'返回数据为:'
+{
this
.state.msg}
</Text>
<CustomButton text=
'iOS调用访问React Native'
onPress={()=>RNBridgeModule.VCOpenRN({
'name'
:
'jiangqqlmj'
})}
/>
</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'
, () => hunheDemo);
5.3.运行效果图
(六)最后总结
今天我们主要学习一下React Native iOS开发中,RN和原生iOS混合开发以及数据相互传输详解。
刚创建的React Native交流6群:426762904,欢迎各位大牛,React Native技术爱好者加入交流!同时博客右侧欢迎微信扫描关注订阅号,移动技术干货,精彩文章技术推送!
本文章实例项目地址:https://github.com/jiangqqlmj/hunheDemo
尊重原创,未经授权不得转载:From Sky丶清(http://www.lcode.org/) 侵权必究!
关注我的订阅号(codedev123),每天分享移动开发技术(Android/IOS),项目管理以及博客文章!(欢迎关注,第一时间推送精彩文章)
关注我的微博,可以获得更多精彩内容
- 【React Native开发】React Native 进阶之原生混合与数据通信开发详解-适配iOS开发(61)
- [React Native混合开发]React Native for iOS之应用
- iOS React Native 混合开发集成React Native
- React Native开发原生Android,IOS教程
- react native与Android混合开发
- React Native混合开发1
- react-native + androidstudio 混合开发
- [React Native混合开发]React Native for iOS之环境搭建
- [React Native混合开发]React Native for iOS之创建第一个案例
- [React Native混合开发]React Native for iOS之代码结构
- [React Native混合开发]React Native for iOS之CSS和UI布局
- [React Native混合开发]React Native for iOS之布局实战
- [React Native混合开发]React Native for iOS之布局实战(二)
- [React Native混合开发]React Native for iOS之UI组件
- [React Native混合开发]React Native for iOS之动手写组件
- [React Native混合开发]React Native for iOS之环境搭建
- React-native、原生混合开发AndroidStudio打包流程(Windows 10)
- React Native 嵌入原生项目混合开发-自定义RN Activity
- Hadoop入门-1.配置部署启动(基于hadoop-2.7.3)
- Oracle Study--Oracle RAC CacheFusion(MindMap)
- 快乐数
- HTML框架建立知识点
- 使用 JAX-RS 简化 REST 应用开发 实例
- 【React Native开发】React Native 进阶之原生混合与数据通信开发详解-适配iOS开发(61)
- 【云解压】ZIP 文件格式分析-偏移计算和文件大小表示ZIP32 ZIP64
- 插入区间
- 开端-对现有知识结构和项目的梳理
- 判断日期是否合法的正则表达式
- 计算机网络原理整体剖析
- HTML学习记录5
- JS简单工厂模式
- php 算法