React-Native的与原生的交互

在用RN开发的时候,遇到一些情况也需要来扩展原生的组件,就需要与OC来交互。

通讯的机制与流程

属性

通过属性(properties)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
属性是最简单的跨组件通信。因此我们需要一个方法从原生组件传递属性到React Native或者从React Native到原生组件。

RCTRootView

RCTRootView将React Natvie视图封装到原生组件中。RCTRootView是一个UIView容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。

原生传递/更新属性->RN

传递属性:参数initialProperties,这个RCTRootView的初始化函数的参数来完成。initialProperties必须是NSDictionary的一个实例。这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。

1
2
3
4
5
6
7
NSArray *imageList = @[@"http://foo.com/bar1.png",
@"http://foo.com/bar2.png"];
NSDictionary *props = @{@"images" : imageList};

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"ImageBrowserApp"
initialProperties:props];

就可以把ImageBrowserApp作为RN的一个组件。
AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);

更新属性:RCTRootView同样提供了一个可读写的属性appProperties。在appProperties设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。

1
2
3
NSArray *imageList = @[@"http://foo.com/bar3.png",
@"http://foo.com/bar4.png"];
rootView.appProperties = @{@"images" : imageList};

RN传递属性->原生

在你自定义的原生组件中通过RCT_CUSTOM_VIEW_PROPERTY宏导出属性,就可以直接在React Native中使用,就好像它们是普通的React Native组件一样。

自定义Native API组件(原生模块)

在React Native中,一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类,其中RCT是ReaCT的缩写。
JS中也可以使用的Objective-C的类。每一个模块的实例都是在每一次通过JS bridge通信时创建的。

模块和方法的定义

模块类就是一个实现了RCTBridgeModule协议的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
// CalendarManager.h
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>

@interface CalendarManager : NSObject <RCTBridgeModule>
@end

@implementation CalendarManager

// 必须实现
RCT_EXPORT_MODULE();

@end

为了实现RCTBridgeModule协议,你的类需要包含RCT_EXPORT_MODULE()宏.

RCT_EXPORT_MODULE();//向系统注册模块
RCT_REMAP_METHOD();//暴露模块方法

普通调用

  1. OC中声明要给Javascript导出的方法,通过RCT_EXPORT_METHOD()宏来实现:
    JavaScript和OC之间要通信,完成数据类型的转化,标准的JSON的类型都是支持的。

现在从Javascript里可以这样调用:
首先,先导入和声明原生模块:

1
2
3
4
//  导入NativeModules
import { NativeModules } from 'react-native';
// 声明CalendarManager
var CalendarManager = NativeModules.CalendarManager;

// 调用原生方法
CalendarManager.addEvent('调用testNormalEvent方法', '测试普通调用')

参数类型
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类型或类。

回调函数

原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给JavaScript。

(^RCTResponseSenderBlock)(NSArray )接收多个参数的回调函数
(^RCTRespomseErrorBlock)(NSError
)接受错误参数的回调函数
(^RCTPromiseResolveBlock)(id result):处理Promise Resolve
(^RCTPromiseRejectBlock)(NSError *):处理Promise Reject

Promises

使用promise来简化代码,搭配ES2016(ES7)标准的async/await语法则效果更佳。如果桥接原生方法的最后两个参数是RCTPromiseResolveBlock和RCTPromiseRejectBlock,则对应的JS方法就会返回一个Promise对象。

给Javascript发送事件–RCTBridge与RCTEventDispatcher

即使没有被JavaScript调用,本地模块也可以给JavaScript发送事件通知。最直接的方式是使用eventDispatcher:

在Javascript中订阅事件–NativeAppEventEmitter.addListener

1
2
3
4
5
6
7
8
9
import { NativeAppEventEmitter } from 'react-native';

var subscription = NativeAppEventEmitter.addListener(
'EventReminder',
(reminder) => console.log(reminder.name)
);
...
// 千万不要忘记忘记取消订阅, 通常在componentWillUnmount函数中实现。
subscription.remove();

原生UI组件封装

React Native代码与OC代码的互通

为了实现消息互通,需要建立一个原生语言模块负责与React Native桥接

OC代码向React Native发送消息有两种方式:

  • 通过回调接口。这种方式要求React Native代码先将接口传递给OC代码,然后OC代码才可以通过这个回调接口向React Native代码发送消息。
  • 通过eventDispatcher向React Native模块发送事件。这样能够做到OC代码主动向React Native发送消息。
文章目录
  1. 1. 通讯的机制与流程
    1. 1.1. 属性
      1. 1.1.1. RCTRootView
        1. 1.1.1.1. 原生传递/更新属性->RN
      2. 1.1.2. RN传递属性->原生
  2. 2. 自定义Native API组件(原生模块)
    1. 2.1. 模块和方法的定义
      1. 2.1.1. 普通调用
      2. 2.1.2. 回调函数
      3. 2.1.3. Promises
      4. 2.1.4. 给Javascript发送事件–RCTBridge与RCTEventDispatcher
      5. 2.1.5. 在Javascript中订阅事件–NativeAppEventEmitter.addListener
  3. 3. 原生UI组件封装
  4. 4. React Native代码与OC代码的互通
本站总访问量 本站访客数人次 ,