怎么从react-react native点击跳转页面跳转到ios原生viewcontroller

React-Native与iOS原生的集成步骤 - 简书
React-Native与iOS原生的集成步骤
最近准备在公司项目中使用RN,但罗马不是一天建成的,没办法将项目中所有的代码都换成RN,而且我也不认为全换成RN就是好的,所以准备先将项目中的一些页面改成RN开发。这篇文章就是与iOS原生集成的步骤。我将项目更新到了github上,里面有很多我自己的理解,希望可以帮到各位读者
如果遇到什么问题可以在评论区回复,或者加QQ群讨论
前提:电脑已经安装过React-Native相关环境;创建:首先我们创建一个iOS项目,我命名为React-iOS;
使用Cocoapods(官方推荐的办法,如果想在项目中使用Cocoapods可以找一下唐巧写的安装教程)
创建Podfile Cocoapods通过解析Podfile指定的工程文件进行依赖安装,我们在工程目录下创建一个Podfile文件: platform :ios, ‘7.0’
target ‘React-iOS’ do
pod 'React-iOS', :path =& './node_modules/react-native', :subspecs =& [
'RCTImage',
'RCTNetwork',
'RCTText',
'RCTWebSocket',
# 添加你的项目中需要的其他三方库
注意:要添加所有你需要的依赖。举例来说,元素如果不添加RCTText依赖就不能运行。
依赖文件安装 进入工程目录,执行$ pod install,就完成了react-native工程包的集成。
打开React-iOS.xcworkspace Cocoapods安装成功之后,工程目录会产生一个React-iOS.xcworkspace的工程文件,我们使用Xcode打开这个工程打开这个工程文件。
不使用Cocoapods,手动集成
1.安装react-native我们在React-iOS项目目录建一个reactnative目录,用于存放我们的react-native相关文件,再创建一个package.json文件,用于初始化react-native。
文件夹截图.png
//package.json
//dependencies中的react指的是React的版本号,react-native就是React-Native的版本号啦~
"name": "React-iOS",
"version": "0.0.1",
"private": true,
"dependencies": {
"react": "^15.3.1",
"react-native": "^0.32.0"
执行安装:$ cd reactnative $ npm install安装成功后,reactnative目录会产生一个node_modules,里面就是react-native依赖的所有项目包。 2.创建index.ios.js文件在reactnative目录下创建index.ios.js文件:
import React, { Component } from 'react';
AppRegistry,
StyleSheet,
TouchableOpacity,
} from 'react-native';
class ReactiOS extends Component {
render() {
&View style={styles.container}&
&Text&Hello World!&/Text&
const styles = StyleSheet.create({
container: {
backgroundColor : 'red ',
height:100,
flexDirection : 'row '
AppRegistry.registerComponent('ReactiOS', () =& ReactiOS);
这就是我们js程序的入口文件。ok,以上我们已经完成react-native的准备工作,接下来要开始集成啦~3.手动集成react-native
添加react-native工程文件由于项目没有使用Cocoapods进行第三方依赖包管理,所有我们需要手动将react-native工程包添加到我们的原生ios工程中。打开reactnative/node_modules/react-native目录,找到相关的项目包,将React相关的工程包手动添加到项目中:添加`react-native/React/React.xcodeproj`到项目中
添加`react-native/Libraries/Network/RCTNetwork.xcodeproj`到项目中
添加`react-native/Libraries/Text/RCTText.xcodeproj`到项目中
添加`react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj`到项目中
添加`react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj`到项目中
添加的原则是,你需要什么就添加什么工程包。好了,我们已经将React相关工程包手动添加到React-iOS工程项目的reactnative目录下。
添加相关frameworks文件接下来要将相关的frameworks文件添加到工程中,React-iOS -& TARGETS -& React-iOS -& Build Phases -& Link Binary Width Libraries
添加frameworks.png
将所有.a文件选中并添加
添加.a文件.png
添加搜索头文件的地址React-iOS -& TARGETS -& React-iOS -& Build Settings -& Header Search Paths,添加一条$(SRCROOT)/reactnative/node_modules/react-native/React,选择recursive。这样我们就react-native集成到现有的ios工程中了。错误:
解决方法:在React-iOS -& TARGETS -& React-iOS -& Build Phases -& Link Binary Width Libraries中导入libz.1.1.3.tbd,libstdc++.tbd两个文件
通过上面的步骤,就可以将React-Native项目集成到原有的项目中了,我将在下一篇文章中告诉大家如何运行项目中的RN页面,还有RN跳转到原生页面的方法。
一名iOS开发程序猿,正在往前端的路上越走越远。React Native 与原生之间的通信(iOS)_IOS开发-织梦者
当前位置:&>&&>& > React Native 与原生之间的通信(iOS)
React Native 与原生之间的通信(iOS)
本文将讲述下在原生和React Native之间的通信方式。方式和逻辑综合了自己的思维方式,主要参考了React Native中文官方文档,因为感觉它讲的方式有些不妥,所以就按自己思路组织了下文。
虽然发觉一遍文章要把所有通信方式讲清楚不太科学,不过把思路讲讲倒是可以,总体思路是,原生和React Native之间的通信方式主要包括三大部分:
属性原生模块原生UI组件封装
(下文主要详细讲了前两部分,最后一部分还在研究,等待更新中)
React Native是从React中得到的灵感,因此基本的信息流是类似的。在React中信息是单向的。我们维护了组件层次,在其中每个组件都仅依赖于它父组件和自己的状态。通过属性(properties)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
属性是最简单的跨组件通信。因此我们需要一个方法从原生组件传递属性到React Native或者从React Native到原生组件。
原生给JS传数据,主要依靠属性。
通过initialProperties,这个RCTRootView的初始化函数的参数来完成。
RCTRootView还有一个appProperties属性,修改这个属性,JS端会调用相应的渲染方法。
我们使用RCTRootView将React Natvie视图封装到原生组件中。RCTRootView是一个UIView容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。
1. 从原生组件传递属性到React Native(原生-&rn)
通过RCTRootView的初始化函数你可以将任意属性传递给React Native应用。参数initialProperties必须是NSDictionary的一个实例。这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。
原生oc代码:
NSArray *imageList = @[@&/bar1.png&,
@&/bar2.png&];
NSDictionary *props = @{@&images& : imageList};
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@&ImageBrowserApp&
initialProperties:props];
js处理代码:
'use strict';
import React, { Component } from 'react';
AppRegistry,
} from 'react-native';
class ImageBrowserApp extends Component {
renderImage(imgURI) {
&Image source={{uri: imgURI}} /&
render() {
{this.props.images.map(this.renderImage)}
AppRegistry.registerComponent('ImageBrowserApp', () =& ImageBrowserApp);
2. 从原生组件更新属性到React Native(原生-&rn)
RCTRootView同样提供了一个可读写的属性appProperties。在appProperties设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。
NSArray *imageList = @[@&/bar3.png&,
@&/bar4.png&];
rootView.appProperties = @{@&images& : imageList};
你可以随时更新属性,但是更新必须在主线程中进行,读取则可以在任何线程中进行。
更新属性时并不能做到只更新一部分属性。我们建议你自己封装一个函数来构造属性。
注意:目前,最顶层的RN组件(即registerComponent方法中调用的那个)的componentWillReceiveProps和componentWillUpdateProps方法在属性更新后不会触发。但是,你可以通过componentWillMount访问新的属性值。
3. 从React Native传递属性到原生组件(rn-&原生)
在你自定义的原生组件中通过RCT_CUSTOM_VIEW_PROPERTY宏导出属性,就可以直接在React Native中使用,就好像它们是普通的React Native组件一样。
更详细的“原生UI组件封装”部分会讲到。
二、原生模块
原生模块是JS中也可以使用的Objective-C类。一般来说这样的每一个模块的实例都是在每一次通过JS bridge通信时创建的。他们可以导出任意的函数和常量给React Native。相关细节可以参阅这篇文章。
事实上原生模块的单实例模式限制了嵌入。假设我们有一个React Native组件被嵌入了一个原生视图,并且我们希望更新原生的父视图。使用原生模块机制,我们可以导出一个函数,不仅要接收预设参数,还要接收父视图的标识。这个标识将会用来获得父视图的引用以更新父视图。那样的话,我们需要维持模块中标识到原生模块的映射。 虽然这个解决办法很复杂,它仍被用在了管理所有React Native视图的RCTUIManager类中,原生模块同样可以暴露已有的原生库给JS,地理定位库就是一个现成的例子。
警告:所有原生模块共享同一个命名空间。创建新模块时注意命名冲突。
在React Native中,一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类,其中RCT是ReaCT的缩写。
// CalendarManager.h
#import &RCTBridgeModule.h&
@interface CalendarManager : NSObject &RCTBridgeModule&
为了实现RCTBridgeModule协议,你的类需要包含RCT_EXPORT_MODULE()宏。这个宏也可以添加一个参数用来指定在中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字。
// CalendarManager.m
@implementation CalendarManager
RCT_EXPORT_MODULE(CalendarManager);
你必须明确的声明要给Javascript导出的方法,否则React Native不会导出任何方法。
1. 普通调用
OC中声明要给Javascript导出的方法,通过RCT_EXPORT_METHOD()宏来实现:
对外提供调用方法(testNormalEvent为方法名,后面为参数,按顺序和对应数据类型在js进行传递)
RCT_EXPORT_METHOD(testNormalEvent:(NSString *)name forSomething:(NSString *)thing){
NSString *info = [NSString stringWithFormat:@&Test: %@\nFor: %@&, name, thing];
NSLog(@&%@&, info);
现在从Javascript里可以这样调用:
首先,先导入和声明原生模块:
导入NativeModules
import { NativeModules } from 'react-native';
声明CalendarManager
var CalendarManager = NativeModules.CalendarM
然后,再进行调用:
调用原生方法
CalendarManager.addEvent('调用testNormalEvent方法', '测试普通调用')
导出到Javascript的方法名是Objective-C的方法名的第一个部分。React Native还定义了一个RCT_REMAP_METHOD()宏,它可以指定Javascript方法名。当许多方法的第一部分相同的时候用它来避免在Javascript端的名字冲突。
桥接到Javascript的方法返回值类型必须是void。React Native的桥接操作是异步的,所以要返回结果给Javascript,你必须通过回调或者触发事件来进行。
RCT_EXPORT_METHOD 支持所有标准JSON类型,包括:
string (NSString)number (NSInteger, float, double, CGFloat, NSNumber)boolean (BOOL, NSNumber)array (NSArray) 包含本列表中任意类型object (NSDictionary) 包含string类型的键和本列表中任意类型的值function (RCTResponseSenderBlock)
除此以外,任何RCTConvert类支持的的类型也都可以使用(参见RCTConvert了解更多信息)。RCTConvert还提供了一系列辅助函数,用来接收一个JSON值并转换到原生Objective-C类型或类。
特殊参数类型处理(Date对象)
在我们的CalendarManager例子里,我们需要把事件的时间交给原生方法。我们不能在桥接通道里传递Date对象,所以需要把日期转化成字符串或数字来传递。我们可以这么实现原生函数:
RCT_EXPORT_METHOD(testDateEventOne:(NSString *)name forSomething:(NSString *)thing data:(NSNumber*)secondsSinceUnixEpoch)
NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
或者这样:
RCT_EXPORT_METHOD(testDateEventTwo:(NSString *)name forSomething:(NSString *)thing date:(NSString *)ISO8601DateString)
NSDate *date = [RCTConvert NSDate:ISO8601DateString];
不过我们可以依靠自动类型转换的特性,跳过手动的类型转换,而直接这么写:
RCT_EXPORT_METHOD(testDateEvent:(NSString *)name forSomething:(NSString *)thing date:(NSDate *)date)
// Date is ready to use!
在Javascript既可以这样:
var date = new Date();
// 把日期以unix时间戳形式传递
CalendarManager.testDateEvent('调用testDateEvent方法', '测试date格式', date.getTime());
也可以这样:
// 把日期以ISO-8601的字符串形式传递
CalendarManager.testDateEvent('调用testDateEvent方法', '测试date格式', date.toISOString());
两个值都会被转换为正确的NSDate类型。但如果提供一个不合法的值,譬如一个Array,则会产生一个“红屏”报错信息。
dictionary参数
随着CalendarManager.addEvent方法变得越来越复杂,参数的个数越来越多,其中有一些可能是可选的参数。在这种情况下我们应该考虑修改我们的API,用一个dictionary来存放所有的事件参数,像这样:
对外提供调用方法,为了演示事件传入属性字段
RCT_EXPORT_METHOD(testDictionaryEvent:(NSString *)name details:(NSDictionary *) dictionary)
NSString *location = [RCTConvert NSString:dictionary[@&thing&]];
NSDate *time = [RCTConvert NSDate:dictionary[@&time&]];
NSString *description=[RCTConvert NSString:dictionary[@&description&]];
NSString *info = [NSString stringWithFormat:@&Test: %@\nFor: %@\nTestTime: %@\nDescription: %@&,name,location,time,description];
NSLog(@&%@&, info);
然后在JS里这样调用:
CalendarManager.testDictionaryEvent('调用addEventMoreDetails方法', {
thing:'测试字典(字段)格式',
time:date.getTime(),
description:'就是这么简单~'
注意: 关于数组和映射
Objective-C并没有提供确保这些结构体内部值的类型的方式。你的原生模块可能希望收到一个字符串数组,但如果JavaScript在调用的时候提供了一个混合number和string的数组,你会收到一个NSArray,里面既有NSNumber也有NSString。对于数组来说,RCTConvert提供了一些类型化的集合,譬如NSStringArray或者UIColorArray,你可以用在你的函数声明中。对于映射而言,开发者有责任自己调用RCTConvert的辅助方法来检测和转换值的类型。
2. 回调函数
原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。
对外提供调用方法,演示Callback
RCT_EXPORT_METHOD(testCallbackEvent:(RCTResponseSenderBlock)callback)
NSArray *events=@[@&callback &, @&test &, @& array&];
callback(@[[NSNull null],events]);
RCTResponseSenderBlock只接受一个参数——传递给JavaScript回调函数的参数数组。在上面这个例子里我们用Node.js的常用习惯:第一个参数是一个错误对象(没有发生错误的时候为null),而剩下的部分是函数的返回值。
CalendarManager.testCallbackEvent((error, events) =& {
if (error) {
console.error(error);
this.setState({events: events});
原生模块通常只应调用回调函数一次。但是,它可以保存callback并在将来调用。这在封装那些通过“委托函数”来获得返回值的iOS API时最为常见。RCTAlertManager中就属于这种情况。
如果你想传递一个更接近Error类型的对象给Javascript,可以用RCTUtils.h提供的RCTMakeError函数。现在它仅仅是发送了一个和Error结构一样的dictionary给Javascript,但我们考虑在将来版本里让它产生一个真正的Error对象。
3. Promises
(译注:这一部分涉及到较新的js语法和特性,不熟悉的读者建议先阅读ES6的相关书籍和文档。)
原生模块还可以使用promise来简化代码,ES2016(ES7)标准的async/await语法则效果更佳。如果桥接原生方法的最后两个参数是RCTPromiseResolveBlock和RCTPromiseRejectBlock,则对应的JS方法就会返回一个Promise对象。
我们把上面的代码用promise来代替回调进行重构:
对外提供调用方法,演示Promise使用
RCT_REMAP_METHOD(testPromiseEvent,
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
NSArray *events =@[@&Promise &,@&test &,@& array&];
if (events) {
resolve(events);
NSError *error=[NSError errorWithDomain:@&我是Promise回调错误信息...& code:101 userInfo:nil];
reject(@&no_events&, @&There were no events&, error);
现在JavaScript端的方法会返回一个Promise。这样你就可以在一个声明了async的异步函数内使用await关键字来调用,并等待其结果返回。(虽然这样写着看起来像同步操作,但实际仍然是异步的,并不会阻塞执行来等待)。
//获取Promise对象处理
async updateEvents(){
console.log('updateEvents');
var events=await CalendarManager.testPromiseEvent();
this.setState({events});
}catch(e){
console.error(e);
在对应位置调用
this.updateE
原生模块不应对自己被调用时所处的线程做任何假设。React Native在一个独立的串行GCD队列中调用原生模块的方法,但这属于实现的细节,并且可能会在将来的版本中改变。
通过实现方法- (dispatch_queue_t)methodQueue,原生模块可以指定自己想在哪个队列中被执行。具体来说,如果模块需要调用一些必须在主线程才能使用的API,那应当这样指定:
- (dispatch_queue_t)methodQueue
return dispatch_get_main_queue();
类似的,如果一个操作需要花费很长时间,原生模块不应该阻塞住,而是应当声明一个用于执行操作的独立队列。举个例子,RCTAsyncLocalStorage模块创建了自己的一个queue,这样它在做一些较慢的磁盘操作的时候就不会阻塞住React本身的消息队列:
- (dispatch_queue_t)methodQueue
return dispatch_queue_create(&com.facebook.React.AsyncLocalStorageQueue&, DISPATCH_QUEUE_SERIAL);
指定的methodQueue会被你模块里的所有方法共享。如果你的方法中“只有一个”是耗时较长的(或者是由于某种原因必须在不同的队列中运行的),你可以在函数体内用dispatch_async方法来在另一个队列执行,而不影响其他方法:
RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 在这里执行长时间的操作
// 你可以在任何线程/队列中执行回调函数
callback(@[...]);
注意: 在模块之间共享分发队列
methodQueue方法会在模块被初始化的时候被执行一次,然后会被React Native的桥接机制保存下来,所以你不需要自己保存队列的引用,除非你希望在模块的其它地方使用它。但是,如果你希望在若干个模块中共享同一个队列,则需要自己保存并返回相同的队列实例;仅仅是返回相同名字的队列是不行的。
这里有一点需要注意,若是要对原生的UI进行操作,则必须在主线程中进行,即影响原生UI的方法要调用:
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI in UI thread here
也可实现methodQueue方法,将全部方法在主线程中执行(不推荐)。
5. 导出常量
原生模块可以导出一些常量,这些常量在JavaScript端随时都可以访问。用这种方法来传递一些静态数据,可以避免通过bridge进行一次来回交互。
- (NSDictionary *)constantsToExport
return @{ @&firstDayOfTheWeek&: @&Monday& };
Javascript端可以随时同步地访问这个数据:
console.log(CalendarManager.firstDayOfTheWeek);
但是注意这个常量仅仅在初始化的时候导出了一次,所以即使你在运行期间改变constantToExport返回的值,也不会影响到JavaScript环境下所得到的结果。
6. 枚举常量
用NS_ENUM定义的枚举类型必须要先扩展对应的RCTConvert方法才可以作为函数参数传递。
假设我们要导出如下的NS_ENUM定义:
typedef NS_ENUM(NSInteger, UIStatusBarAnimation) {
UIStatusBarAnimationNone,
UIStatusBarAnimationFade,
UIStatusBarAnimationSlide,
你需要这样来扩展RCTConvert类:
@implementation RCTConvert (StatusBarAnimation)
RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{ @&statusBarAnimationNone& : @(UIStatusBarAnimationNone),
@&statusBarAnimationFade& : @(UIStatusBarAnimationFade),
@&statusBarAnimationSlide& : @(UIStatusBarAnimationSlide)}),
UIStatusBarAnimationNone, integerValue)
接着你可以这样定义方法并且导出enum值作为常量:
- (NSDictionary *)constantsToExport
return @{ @&statusBarAnimationNone& : @(UIStatusBarAnimationNone),
@&statusBarAnimationFade& : @(UIStatusBarAnimationFade),
@&statusBarAnimationSlide& : @(UIStatusBarAnimationSlide) }
RCT_EXPORT_METHOD(updateStatusBarAnimation:(UIStatusBarAnimation)animation
completion:(RCTResponseSenderBlock)callback)
你的枚举现在会用上面提供的选择器进行转换(上面的例子中是integerValue),然后再传递给你导出的函数。
7. 给Javascript发送事件
即使没有被JavaScript调用,本地模块也可以给JavaScript发送事件通知。最直接的方式是使用eventDispatcher:
#import &RCTBridge.h&
#import &RCTEventDispatcher.h&
@implementation CalendarManager
@synthesize bridge = _
进行设置发送事件通知给JavaScript端
- (void)calendarEventReminderReceived:(NSNotification *)notification
NSString *name = [notification userInfo][@&name&];
[self.bridge.eventDispatcher sendAppEventWithName:@&EventReminder&
body:@{@&name&: name}];
在JavaScript中可以这样订阅事件:
import { NativeAppEventEmitter } from 'react-native';
var subscription = NativeAppEventEmitter.addListener(
'EventReminder',
(reminder) =& console.log(reminder.name)
// 千万不要忘记忘记取消订阅, 通常在componentWillUnmount函数中实现。
subscription.remove();
8. 从Swift导出
Swift不支持宏,所以从Swift向React Native导出类和函数需要多做一些设置,但是大致与Objective-C是相同的。
假设我们已经有了一个一样的CalendarManager,不过是用Swift实现的类:
// CalendarManager.swift
@objc(CalendarManager)
class CalendarManager: NSObject {
@objc func addEvent(name: String, location: String, date: NSNumber) -& Void {
// Date is ready to use!
注意: 你必须使用@objc标记来确保类和函数对Objective-C公开。
接着,创建一个私有的实现文件,并将必要的信息注册到React Native中。
// CalendarManagerBridge.m
#import &RCTBridgeModule.h&
@interface RCT_EXTERN_MODULE(CalendarManager, NSObject)
RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)
请注意,一旦你在IOS中混用2种语言, 你还需要一个额外的桥接头文件,称作“bridging header”,用来导出Objective-C文件给Swift。如果你是通过Xcode菜单中的File&New File来创建的Swift文件,Xcode会自动为你创建这个头文件。在这个头文件中,你需要引入RCTBridgeModule.h。
// CalendarManager-Bridging-Header.h
#import &RCTBridgeModule.h&
也可以使用RCT_EXTERN_REMAP_MODULE和RCT_EXTERN_REMAP_METHOD来改变导出模块和方法的JavaScript调用名称。
这一part的编写主要参考自官方中文文档:原生模块,因为觉得官方的讲述不太清楚,所以自己进行了部分修改,结合了江清清的demo,为了更清晰的展示原生模块和RN之间的交互,将RN部分和原生部分在同一页面中展示,demo如下(上部分为RN页面,下部分为原生view):
demo暂时上传至百度云:/s/1hrMVNta
rn&原生test.gif
去掉原生UI,部分(可运行)代码如下:
原生OC代码:
#import &CalendarManager.h&
#import &RCTConvert.h&
#import &RCTBridge.h&
#import &RCTEventDispatcher.h&
@implementation CalendarManager
@synthesize bridge=_
RCT_EXPORT_MODULE()
指定执行模块里的方法所在的队列
- (dispatch_queue_t)methodQueue
return dispatch_get_main_queue();
在完整demo中才有用到,用于更新原生UI
- (void)showInfo:(NSString *)info
更新UI操作在主线程中执行
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI in UI thread here
[[NSNotificationCenter defaultCenter] postNotificationName:@&react_native_test& object:nil userInfo:@{@&info&: info}];
- (void)showDate:(NSDate *)date withName:(NSString *)name forSomething:(NSString *)thing
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateFormat:@&yyyy-MM-dd&];
NSString *info = [NSString stringWithFormat:@&Test: %@\nFor: %@\nTestTime: %@&, name, thing,[formatter stringFromDate:date]];
NSLog(@&%@&, info);
对外提供调用方法
RCT_EXPORT_METHOD(testNormalEvent:(NSString *)name forSomething:(NSString *)thing)
NSString *info = [NSString stringWithFormat:@&Test: %@\nFor: %@&, name, thing];
NSLog(@&%@&, info);
对外提供调用方法,为了演示事件时间格式化 secondsSinceUnixEpoch
RCT_EXPORT_METHOD(testDateEventOne:(NSString *)name forSomething:(NSString *)thing data:(NSNumber*)secondsSinceUnixEpoch)
NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
[self showDate:date withName:name forSomething:thing];
对外提供调用方法,为了演示事件时间格式化 ISO8601DateString
RCT_EXPORT_METHOD(testDateEventTwo:(NSString *)name forSomething:(NSString *)thing date:(NSString *)ISO8601DateString)
NSDate *date = [RCTConvert NSDate:ISO8601DateString];
[self showDate:date withName:name forSomething:thing];
对外提供调用方法,为了演示事件时间格式化 自动类型转换
RCT_EXPORT_METHOD(testDateEvent:(NSString *)name forSomething:(NSString *)thing date:(NSDate *)date)
[self showDate:date withName:name forSomething:thing];
对外提供调用方法,为了演示事件传入属性字段
RCT_EXPORT_METHOD(testDictionaryEvent:(NSString *)name details:(NSDictionary *) dictionary)
NSString *location = [RCTConvert NSString:dictionary[@&thing&]];
NSDate *time = [RCTConvert NSDate:dictionary[@&time&]];
NSString *description=[RCTConvert NSString:dictionary[@&description&]];
NSString *info = [NSString stringWithFormat:@&Test: %@\nFor: %@\nTestTime: %@\nDescription: %@&,name,location,time,description];
NSLog(@&%@&, info);
对外提供调用方法,演示Callback
RCT_EXPORT_METHOD(testCallbackEvent:(RCTResponseSenderBlock)callback)
NSArray *events=@[@&callback &, @&test &, @& array&];
callback(@[[NSNull null],events]);
对外提供调用方法,演示Promise使用
RCT_REMAP_METHOD(testPromiseEvent,
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
NSArray *events =@[@&Promise &,@&test &,@& array&];
if (events) {
resolve(events);
NSError *error=[NSError errorWithDomain:@&我是Promise回调错误信息...& code:101 userInfo:nil];
reject(@&no_events&, @&There were no events&, error);
对外提供调用方法,演示Thread使用
RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 在后台执行耗时操作
// You can invoke callback from any thread/queue
callback(@[[NSNull null],@&耗时操作执行完成...&]);
进行设置封装常量给JavaScript进行调用
-(NSDictionary *)constantsToExport
// 此处定义的常量为js订阅原生通知的通知名
return @{@&receiveNotificationName&:@&receive_notification_test&};
开始订阅通知事件
RCT_EXPORT_METHOD(startReceiveNotification:(NSString *)name)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(calendarEventReminderReceived:)
object:nil];
进行设置发送事件通知给JavaScript端(这里需要注意,差一个触发通知点,需自己想办法加上,或者看完整demo)
- (void)calendarEventReminderReceived:(NSNotification *)notification
NSString *name = [notification userInfo][@&name&];
[self.bridge.eventDispatcher sendAppEventWithName:@&EventReminder&
body:@{@&name&: name}];
* Sample React Native App
* /facebook/react-native
import React, { Component } from 'react';
AppRegistry,
StyleSheet,
ScrollView,
TouchableHighlight
} from 'react-native';
NativeModules,
NativeAppEventEmitter
} from 'react-native';
var CalendarManager = NativeModules.CalendarM
class CustomButton ponent {
render() {
&TouchableHighlight
style={{padding: 8, backgroundColor:this.props.backgroundColor}}
underlayColor=&#a5a5a5&
onPress={this.props.onPress}&
&Text&{this.props.text}&/Text&
&/TouchableHighlight&
class ModulesDemo extends Component {
constructor(props){
super(props);
this.state={
events:'',
notice:'',
componentDidMount(){
console.log('开始订阅通知...');
this.receiveNotification();
subscription = NativeAppEventEmitter.addListener(
'EventReminder',
(reminder) =& {
console.log('通知信息:'+reminder.name)
this.setState({notice:reminder.name});
receiveNotification(){
CalendarManager.receiveNotificationName 为原生定义常量
CalendarManager.startReceiveNotification(CalendarManager.receiveNotificationName);
componentWillUnmount(){
subscription.remove();
//获取Promise对象处理
async updateEvents(){
console.log('updateEvents');
var events=await CalendarManager.testPromiseEvent();
this.setState({events});
}catch(e){
console.error(e);
render() {
var date = new Date();
&ScrollView&
&Text style={{fontSize: 16, textAlign: 'center', margin: 10}}&
&View style={{borderWidth: 1,borderColor: '#000000'}}&
&Text style={{fontSize: 15, margin: 10}}&
普通调用原生模块方法
&CustomButton text=&调用testNormalEvent方法-普通&
backgroundColor= &#FF0000&
onPress={()=&CalendarManager.testNormalEvent('调用testNormalEvent方法', '测试普通调用')}
&CustomButton text=&调用testDateEvent方法-日期处理&
backgroundColor= &#FF7F00&
onPress={()=&CalendarManager.testDateEvent('调用testDateEvent方法', '测试date格式',date.getTime())}
&CustomButton text=&调用testDictionaryEvent方法-字典&
backgroundColor= &#FFFF00&
onPress={()=&CalendarManager.testDictionaryEvent('调用testDictionaryEvent方法', {
thing:'测试字典(字段)格式',
time:date.getTime(),
description:'就是这么简单~'
&Text style={{fontSize: 15, margin: 10}}&
'Callback返回数据:{this.state.events}
&CustomButton text=&调用原生模块testCallbackEvent方法-Callback&
backgroundColor= &#00FF00&
onPress={()=&CalendarManager.testCallbackEvent((error,events)=&{
if(error){
console.error(error);
this.setState({events:events,});
&CustomButton text=&调用原生模块testPromiseEvent方法-Promise&
backgroundColor= &#00FFFF&
onPress={()=&this.updateEvents()}
&View style={{borderWidth: 1,borderColor: '#000000'}}&
&Text style={{fontSize: 15, margin: 10}}&
原生调js,接收信息:{this.state.notice}
&/ScrollView&
AppRegistry.registerComponent('NativeTest', () =& ModulesDemo);
三、原生UI组件封装
在如今的App中,已经有成千上万的原生UI部件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如ScrollView和TextInput,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
以上就是React Native 与原生之间的通信(iOS)的全文介绍,希望对您学习和使用ios应用开发有所帮助.
这些内容可能对你也有帮助
更多可查看IOS开发列表页。
猜您也会喜欢这些文章

我要回帖

更多关于 原生跳转react native 的文章

 

随机推荐