react native 学习之 native modules
翻译自https://facebook.github.io/react-native/docs/native-modules-ios.html
Native Modules
很多情况下,app需要使用原生的api,或者是用一些已经用OC、Swift或C++写好的模块,又或者需要写出更高效率的、或多线程的代码来支撑图像处理、数据库或其它高要求的需求。
React Native的设计当然是支持我们使用原生特性的,以使平台本身的能力得以完全发挥。不过这相对来说是比较进阶的功能,他们的存在虽然是必要的,但在日常开发中并不是必须要用到的。如果RN不支持摸个你想要用到的原生特性,你可以自己做支持。
这是一个高阶教程,介绍了如何搭建一个原生模块。阅读者需要对OC或Swift以及一些核心原生模块(eg.Foundation, UIKit)有一定的了解。
iOS Calendar Module Example
本教程以iOS Calendar Api为例。我们要通过JavaScript来使用iOS calendar。
一个原生模块,就是一个实现了RCTBridgeModule协议的Objective-C类。RCT是ReaCT的缩写。
// CalendarManager.h
#import <React/RCTBridgeModule.h> @interface CalendarManager : NSObject <RCTBridgeModule>
@end
除了要实现RCTBridgeModule协议之外,还需要执行RCT_EXPORT_MODULE()宏指令,它接受的第一个参数,表示这个模块在JavaScript中使用时的引用名。如果没有传这个参数,那默认OC的类名就是js中的引用名。
// CalendarManager.m
@implementation CalendarManager // To export a module named CalendarManager
RCT_EXPORT_MODULE(); // This would name the module AwesomeCalendarManager instead
// RCT_EXPORT_MODULE(AwesomeCalendarManager); @end
如果需要在js中使用CalendarManager中的方法,需要使用RCT_EXPORT_METHOD()宏指令,将方法暴露出去。
#import "CalendarManager.h"
#import <React/RCTLog.h> @implementation CalendarManager RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
暴露出去之后,在js文件中调用该方法的方式如下:
import { NativeModules } from 'react-native';
var CalendarManager = NativeModules.CalendarManager;
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
注:JavaScript中的方法名称
暴露到JavaScript中的原生方法的方法名就是原生方法名第一个冒号前的内容。另外,RN定义了一个宏指令RCT_REMAP_METHOD(),可以用来制定方法在JavaScript中的方法名。当原生代码中暴露出去的不同的方法的方法名,第一个逗号前有相同的内容时,在JavaScript中方法名就会冲突,这个宏指令就用得上了。
暴露的原生方法的返回值类型只能是void,因为React Native的bridge是异步的,所以向JavaScript传递原生方法的调用结果的方式只能通过回调函数或注册事件的方式。
Argument Types
RCT_EXPORT_METHOD支持所有标准的JSON格式的对象类型,如:
- string (
NSString
) - number (
NSInteger
,float
,double
,CGFloat
,NSNumber
) - boolean (
BOOL
,NSNumber
) - array (
NSArray
) of any types from this list - object (
NSDictionary
) with string keys and values of any type from this list - function (
RCTResponseSenderBlock
)
同时也支持RCTConvert class支持的类型。RCTConvert的helper functions接收JSON值,将其转化为Objective-C的类型或类。
在我们CalendarManager的例子中,我们想要将日期传给远胜方法,但是我们不能直接传js的Date类型的对象,我们需要将data类型的对象转换成字符串或数字。原生方法可以这样写:
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)secondsSinceUnixEpoch)
{
NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch];
}
或者这样:
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSString *)ISO8601DateString)
{
NSDate *date = [RCTConvert NSDate:ISO8601DateString];
}
不过我们也可以使用自动类型转换,省去手动转换的步骤:
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSDate *)date) { // Date is ready to use! }
在js中调用的方式如下:
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.getTime()); // passing date as number of seconds since Unix epoch
// or
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.toISOString()); // passing date as ISO-8601 string
这两种调用都会使原生发放得到正确的NSDate类型的对象。如果是一个不合法的类型,你会看到红盒子的错误信息。
如果CalendarManager.addEvent方法变得越来越复杂,参数的数量会越来越多,而且不是每一个参数都是必要的。这时候就可以考虑,通过字典的形式传入参数。如下:
#import <React/RCTConvert.h> RCT_EXPORT_METHOD(addEvent:(NSString *)name details:(NSDictionary *)details)
{
NSString *location = [RCTConvert NSString:details[@"location"]];
NSDate *time = [RCTConvert NSDate:details[@"time"]];
...
}
在JavaScript中调用:
CalendarManager.addEvent('Birthday Party', {
location: '4 Privet Drive, Surrey',
time: date.getTime(),
description: '...'
})
注:关于array和map
Objective-C不会限制这两种数据结构里的内容的类型。如果原生模块需要一个字符串的数组,而在js中调用的时候,传入了包含数字和字符串的数组,我们在原生方法中会获得既有NSNumber又有NSString类型的NSArray。对于数组,RCTConvert提供了一些约束类型的数据结构永远方法的声明中,例如NSStringArray,UIColorArray。对于maps,开发者需要利用RCTConvert的方法分别取去检查里面的值类型。
Callbacks
原生模块可以接收一个特别的参数:一个js回调函数,作为原生函数执行过程中或执行结束后,向js返回结果并通过js进行进一步处理的方法。
RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback)
{
NSArray *events = ...
callback(@[[NSNull null], events]);
}
RCTResponseSenderBlock只接收一个参数,一个传给js回调函数的参数数组。在我们的例子中,我们的第一个参数是错误信息,作为回调函数参数数组的第一个元素。
CalendarManager.findEvents((error, events) => {
if (error) {
console.error(error);
} else {
this.setState({events: events});
}
})
一个原生模块,应该在方法中立即调用回调函数。也可以将回调函数存下来之后再调用,这常常用在委托中,RCTAlertManager就是一个例子。如果回调函数不被出发,将会造成内存泄漏。如果onSuccess和onFail回调同时存在,只应该调用其中一个。
如果想要传递错误信息对象到js中,用RCTUtils.h提供的RCTMakeError。目前它向js传入了一个error-shaped字典,不过未来会自动生成真正的js的Error对象。
react native 学习之 native modules的更多相关文章
- React Native 学习-01
React Native 学习 (学习版本 0.39) 一.环境配置 二.IDE选择 webstorm 1.webstorm配置 ①.首先是可以选择使用汉化包汉化.eu68 ②.安装插件和外部库. 由 ...
- react native 学习一(环境搭配和常见错误的解决)
react native 学习一(环境搭配) 首页,按照http://reactnative.cn/docs/0.30/getting-started.html#content上的介绍,下载安装pyt ...
- React Native 学习资料
React Native 学习资料 学习资料 网址 React Native中文网 https://reactnative.cn/
- React Native 学习(三)之 FlexBox 布局
React Native 学习(三)之 FlexBox 布局
- React Native 学习笔记--进阶(二)--动画
React Native 进阶(二)–动画 动画 流畅.有意义的动画对于移动应用用户体验来说是非常必要的.我们可以联合使用两个互补的系统:用于全局的布局动画LayoutAnimation,和用于创建更 ...
- node-webkit学习(4)Native UI API 之window
node-webkit学习(4)Native UI API 之window 文/玄魂 目录 node-webkit学习(4)Native UI API 之window 前言 4.1 window a ...
- node-webkit学习(3)Native UI API概览
node-webkit学习(3)Native UI API概览 文/玄魂 目录 node-webkit学习(3)Native UI API概览 前言 3.1 Native UI api概览 Exte ...
- 【优质】React的学习资源
React的学习资源 github 地址: https://github.com/LeuisKen/react-collection https://github.com/reactnativecn/ ...
- (转)2019年 React 新手学习指南 – 从 React 学习线路图说开去
原文:https://www.html.cn/archives/10111 注:本文根据 React 开发者学习线路图(2018) 结构编写了很多新手如何学习 React 的建议.2019 年有标题党 ...
随机推荐
- client.HConnectionManager$HConnectionImplementation: Can't get connection to ZooKeeper: KeeperErrorCode = ConnectionLoss for /hbase
解决方法:hbase 未成功启动 1.关闭防火墙:service iptables stop 2.start-hbase.sh
- DB2自增长ID
建议类似的应用采用sequence对象,将来的应用维护和数据迁移会很方便.考虑的因素较少. 对于序列可以使用nextval和prevval来获得下一个和上一个值:CREATE SEQUENCE seq ...
- python函数、装饰器、迭代器、生成器
目录: 函数补充进阶 函数对象 函数的嵌套 名称空间与作用域 闭包函数 函数之装饰器 函数之迭代器 函数之生成器 内置函数 一.函数补充进阶 1.函数对象: 函数是第一类对象,即函数可以当作数据传递 ...
- FTP中各文件目录的说明
DirectAdmin:FTP中各文件目录的说明 当您使用FTP连上空间后,FTP列表会出现以下文件和目录: domains目录:网站文件存放目录:public_html目录:快捷目录,可以快 ...
- Devexpress VCL Build v2014 vol 14.2.7发布
2015年马上快过去一半了,这个玩意还在纠结在14版.其实也无所谓,反正就是改成15版,也还是这些 东西的修补. What's New in 14.2.7 (VCL Product Line) N ...
- DIV+CSS实战(一)
一.说明 作为一个后台的程序员,我也是很少写前端,最近有一个项目,前端主要是由我来负责,就把我在项目中所学到的东西,记录下来!我的页面要嵌入到另一个系统中,所以,并不是按照传统的top,left,co ...
- SSH整合 第四篇 Spring的IoC和AOP
这篇主要是在整合Hibernate后,测试IoC和AOP的应用. 1.工程目录(SRC) 2.IoC 1).一个Service测试类 /* * 加入spring容器 */ private Applic ...
- (并查集 建立关系)食物链 -- POJ-- 1182
链接: http://poj.org/problem?id=1182 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82830#probl ...
- (最小生成树) 畅通工程再续 -- HDU --1875
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1875 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- 配置使用sourcemap调试vue源码爬坑
环境: Google Chrome V72.0.3626.109 vue-dev V 2.6.10 爬坑的乐趣就不说了(我恨啊),以下说一下出坑要点 1. 在vue-dev的package.json ...