一、原生模块
首先理解原生:https://reactnative.cn/docs/native-modules-android/
二、通信机制
- RN 整体结构以及关键类的类图
RN 最大的优势在于跨平台、热更新。因此,RN 库本身也需要在多个平台(iOS、Android)上运行,从上图可知,在 RN 中 C++与JS部分的实现为多平台共用,在此基础上再分化为各平台实现。
- 用Xcode打开项目,其中,iOS 平台特有的实现(Objective-C、C++)主要集中在 React 下,以C++语言实现的共有部分在 ReactCommon 下:
- 用vscode等软件,打开项目,JS侧与本文关系紧密的内容主要集中在node_modules下的具体路径下,如下图所示:
- 关键类及其间的关系:
如上图:
RCTBridge与RCTCxxBridge属于 iOS 平台特有,前者是 RN 对业务层接口(图中其他类都属于内部类,业务层无感知),具体工作在其子类RCTCxxBridge中完成;
整个 RN 的核心在跨平台的 C++层,其中很多类的功能从其名称即可略知一二,后文也会有详细的描述;
在 RN 中肯定少不了 JS 的支持,从上图可知,JS 与 Native 的通信发生在 JavaScript 与 C++间,这也是本文分析的重点。
说到通信,无外乎 JS to Native、Native to JS,本篇我们重点分析JS to Native。
- JavaScript—>Native
实现 JS to Native 的通信,主要有两条途径:
block——在 RN 这样复杂的应用场景中block显得有些力不从心;
JSExport协议——通过实现该协议可以向 JS 曝露 Native 接口(但不具备跨平台能力)。
因此,RN 并没有使用 JavaScriptCore提供的这两种方式,而是自己实现了一套通信机制。
我们先从一个简单的例子入手:CalendarManager封装了 iOS 平台的日历控件,供 JS 调用。
// CalendarManager.h
#import <React/RCTBridgeModule.h>
@interface CalendarManager : NSObject <RCTBridgeModule>
@end
// CalendarManager.m
@implementation CalendarManager
// To export a module named CalendarManager
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location) {
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
@end
我们知道,要将 Native module(类、接口)曝露给 JS,module需要实现RCTBridgeModule协议,并且在实现中要插入RCT_EXPORT_MODULE宏。具体曝露的方法也需要通过RCT_EXPORT_METHOD宏定义。
// JS
import { NativeModules } from 'react-native';
var CalendarManager = NativeModules.CalendarManager;
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
此时,在 JS 中就可以通过NativeModules.CalendarManager.addEvent(...)方式调用 Native 接口了。
- React Native调用ios原生组件
1.React Native链接原生库
1.1安装
npm install 某个带有原生依赖的库 --save
1.2链接原生依赖
react-native link
1.3手动链接
如果该库包含原生代码,还需要进行手动链接。在库的文件夹下有一个.xcodeproj文件,将文件拖到你的Xcode工程下(通常拖到Xcode的Libraries分组目录下)
1.4导入库
在项目上依次选择[Targets]->[Bulid Phases]->[Link Binary With Libraries]添加第三方类库生成的静态链接库即可
1.5为项目添加查找路径
选择[Targets]->[Build Settings]->[Search Paths]->[UserHeader Search Paths],在参数中加入第三方类库的头文件路径即可,可以是绝对路径(如/Users/libpath),也可以是相对路径(如$(...)/Users),如下图所示
- React Native调用Objective-C创建的原生组件
1.创建一个子类:命名为"视图名称+Manager"。最好避免使用RCT前缀,除非你想把你的组件推送给官方使用
2.添加RCT_EXPORT_MODULE()标记宏:让模块接口暴露给JavaScript.
3.实现-(UIView*)view方法:创建并返回组件视图。
4.封装属性与事件传递
- React Native调用Android原生组件
1.编写原生UI组件
1.1创建子类,实现原生UI管理
1.2创建原生UI管理类,并向系统注册原生UI管理类
2.编写JavaScript端实现
2.1建立私有的JavaScript文件,实现React Native端组件
就是平常写的js文件,此处就不做详细介绍