跳到主要内容

iOS 原生模块

信息

原生模块和原生组件是我们旧有架构中使用的稳定技术。当新架构稳定后,它们将在未来被弃用。新架构使用 Turbo 原生模块Fabric 原生组件 来实现类似的效果。

欢迎来到 iOS 原生模块。请先阅读原生模块介绍,了解原生模块是什么。

创建日历原生模块

在下面的指南中,您将创建一个原生模块 CalendarModule,它将允许您从 JavaScript 访问 Apple 的日历 API。最后,您将能够从 JavaScript 调用 CalendarModule.createCalendarEvent('Dinner Party', 'My House');,从而调用一个创建日历事件的原生方法。

设置

首先,在 Xcode 中打开 React Native 应用程序中的 iOS 项目。您可以在 React Native 应用程序中找到您的 iOS 项目

Image of opening up an iOS project within a React Native app inside of xCode.
显示您可以在何处找到 iOS 项目的图片

我们建议使用 Xcode 编写您的原生代码。Xcode 专为 iOS 开发而构建,使用它将帮助您快速解决诸如代码语法之类的细微错误。

创建自定义原生模块文件

第一步是创建我们的主自定义原生模块头文件和实现文件。创建一个名为 RCTCalendarModule.h 的新文件

Image of creating a class called  RCTCalendarModule.h.
在与 AppDelegate 相同的文件夹中创建自定义原生模块文件的图片

并添加以下内容

Objective-C
//  RCTCalendarModule.h
#import <React/RCTBridgeModule.h>
@interface RCTCalendarModule : NSObject <RCTBridgeModule>
@end

您可以使用任何适合您正在构建的原生模块的名称。将类命名为 RCTCalendarModule,因为您正在创建一个日历原生模块。由于 Objective-C 没有像 Java 或 C++ 那样对命名空间提供语言级支持,因此约定是在类名前添加一个子字符串。这可以是您的应用程序名称或基础设施名称的缩写。本例中的 RCT 指的是 React。

如您所见,CalendarModule 类实现了 RCTBridgeModule 协议。原生模块是实现了 RCTBridgeModule 协议的 Objective-C 类。

接下来,我们开始实现原生模块。使用 Xcode 中的 Cocoa Touch 类在同一文件夹中创建相应的实现文件 RCTCalendarModule.m,并包含以下内容

Objective-C
// RCTCalendarModule.m
#import "RCTCalendarModule.h"

@implementation RCTCalendarModule

// To export a module named RCTCalendarModule
RCT_EXPORT_MODULE();

@end

模块名称

目前,您的 RCTCalendarModule.m 原生模块只包含一个 RCT_EXPORT_MODULE 宏,它将原生模块类导出并注册到 React Native。RCT_EXPORT_MODULE 宏还接受一个可选参数,用于指定模块在 JavaScript 代码中可访问的名称。

此参数不是字符串字面量。在下面的示例中,传递的是 RCT_EXPORT_MODULE(CalendarModuleFoo),而不是 RCT_EXPORT_MODULE("CalendarModuleFoo")

Objective-C
// To export a module named CalendarModuleFoo
RCT_EXPORT_MODULE(CalendarModuleFoo);

然后可以在 JS 中访问原生模块,如下所示

tsx
const {CalendarModuleFoo} = ReactNative.NativeModules;

如果您不指定名称,JavaScript 模块名称将与 Objective-C 类名匹配,并去除所有“RCT”或“RK”前缀。

我们按照下面的例子,不带任何参数调用 RCT_EXPORT_MODULE。结果是,模块将以 CalendarModule 的名称暴露给 React Native,因为这是去除 RCT 后的 Objective-C 类名。

Objective-C
// Without passing in a name this will export the native module name as the Objective-C class name with “RCT” removed
RCT_EXPORT_MODULE();

然后可以在 JS 中访问原生模块,如下所示

tsx
const {CalendarModule} = ReactNative.NativeModules;

将原生方法导出到 JavaScript

除非明确告知,React Native 不会将原生模块中的任何方法暴露给 JavaScript。这可以通过使用 RCT_EXPORT_METHOD 宏来完成。在 RCT_EXPORT_METHOD 宏中编写的方法是异步的,因此返回类型始终为 void。为了将 RCT_EXPORT_METHOD 方法的结果传递给 JavaScript,您可以使用回调或发出事件(下面将介绍)。让我们继续使用 RCT_EXPORT_METHOD 宏为我们的 CalendarModule 原生模块设置一个原生方法。将其命名为 createCalendarEvent(),目前它接受名称和位置参数作为字符串。参数类型选项将在稍后介绍。

Objective-C
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
}

请注意,除非您的方法依赖于 RCT 参数转换(参见下面的参数类型),否则 TurboModules 将不再需要 RCT_EXPORT_METHOD 宏。最终,React Native 将移除 RCT_EXPORT_MACRO,因此我们不鼓励人们使用 RCTConvert。相反,您可以在方法体中进行参数转换。

在您构建 createCalendarEvent() 方法的功能之前,在该方法中添加一个控制台日志,以便您可以确认它已在 React Native 应用程序中从 JavaScript 调用。使用 React 的 RCTLog API。让我们在文件顶部导入该头文件,然后添加日志调用。

Objective-C
#import <React/RCTLog.h>
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}

同步方法

您可以使用 RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD 来创建同步的原生方法。

Objective-C
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getName)
{
return [[UIDevice currentDevice] name];
}

此方法的返回类型必须是对象类型(id),并且应该可以序列化为 JSON。这意味着该 Hook 只能返回 nil 或 JSON 值(例如 NSNumber、NSString、NSArray、NSDictionary)。

目前,我们不建议使用同步方法,因为同步调用方法可能会对性能产生严重影响,并给您的原生模块引入与线程相关的错误。此外,请注意,如果您选择使用 RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD,您的应用程序将无法再使用 Google Chrome 调试器。这是因为同步方法需要 JS VM 与应用程序共享内存。对于 Google Chrome 调试器,React Native 在 Google Chrome 中的 JS VM 内部运行,并通过 WebSockets 与移动设备异步通信。

测试您已构建的内容

至此,您已经为 iOS 中的原生模块设置了基本的脚手架。通过访问原生模块并在 JavaScript 中调用其导出的方法来测试它。

在您的应用程序中找到您希望添加对原生模块 createCalendarEvent() 方法调用的位置。下面是一个组件示例 NewModuleButton,您可以将其添加到您的应用程序中。您可以在 NewModuleButtononPress() 函数中调用原生模块。

tsx
import React from 'react';
import {Button} from 'react-native';

const NewModuleButton = () => {
const onPress = () => {
console.log('We will invoke the native module here!');
};

return (
<Button
title="Click to invoke your native module!"
color="#841584"
onPress={onPress}
/>
);
};

export default NewModuleButton;

为了从 JavaScript 访问您的原生模块,您需要首先从 React Native 导入 NativeModules

tsx
import {NativeModules} from 'react-native';

然后您可以从 NativeModules 中访问 CalendarModule 原生模块。

tsx
const {CalendarModule} = NativeModules;

现在您可以使用 CalendarModule 原生模块了,您可以调用您的原生方法 createCalendarEvent()。下面它被添加到 NewModuleButtononPress() 方法中

tsx
const onPress = () => {
CalendarModule.createCalendarEvent('testName', 'testLocation');
};

最后一步是重建 React Native 应用程序,以便您可以使用最新的原生代码(包含您的新原生模块!)。在命令行中,在 React Native 应用程序所在的目录中,运行以下命令

shell
npm run ios

迭代时的构建

当您阅读这些指南并迭代您的原生模块时,您需要对您的应用程序进行原生重建才能访问 JavaScript 中的最新更改。这是因为您正在编写的代码位于您应用程序的原生部分。虽然 React Native 的 metro 打包器可以监视 JavaScript 中的更改并为您即时重建 JS 包,但它不会对原生代码执行此操作。因此,如果您想测试您的最新原生更改,您需要使用上述命令进行重建。

回顾✨

现在,您应该能够在 JavaScript 中调用您的原生模块上的 createCalendarEvent() 方法。由于您在函数中使用了 RCTLog,因此您可以通过在您的应用程序中启用调试模式并在 Chrome 的 JS 控制台或移动应用程序调试器 Flipper 中查看日志来确认您的原生方法正在被调用。每次调用原生模块方法时,您都应该看到 RCTLogInfo(@"假装创建一个事件 %@ 在 %@", name, location); 消息。

Image of logs.
Flipper 中 iOS 日志的图片

至此,您已经创建了一个 iOS 原生模块,并在您的 React Native 应用程序中从 JavaScript 调用了它的方法。您可以继续阅读以了解更多信息,例如您的原生模块方法接受哪些参数类型以及如何在原生模块中设置回调和 Promise。

日历原生模块之外

更好的原生模块导出

像上面那样通过从 NativeModules 中拉取来导入您的原生模块有点笨重。

为了避免您的原生模块使用者每次想访问您的原生模块时都需要这样做,您可以为模块创建一个 JavaScript 包装器。创建一个名为 NativeCalendarModule.js 的新 JavaScript 文件,内容如下

tsx
/**
* This exposes the native CalendarModule module as a JS module. This has a
* function 'createCalendarEvent' which takes the following parameters:

* 1. String name: A string representing the name of the event
* 2. String location: A string representing the location of the event
*/
import {NativeModules} from 'react-native';
const {CalendarModule} = NativeModules;
export default CalendarModule;

此 JavaScript 文件也成为您添加任何 JavaScript 侧功能的好地方。例如,如果您使用 TypeScript 等类型系统,您可以在此处为您的原生模块添加类型注释。虽然 React Native 尚不支持原生到 JS 的类型安全,但有了这些类型注释,您的所有 JS 代码都将是类型安全的。这些注释还将使您更容易在未来切换到类型安全的原生模块。下面是为日历模块添加类型安全的示例

tsx
/**
* This exposes the native CalendarModule module as a JS module. This has a
* function 'createCalendarEvent' which takes the following parameters:
*
* 1. String name: A string representing the name of the event
* 2. String location: A string representing the location of the event
*/
import {NativeModules} from 'react-native';
const {CalendarModule} = NativeModules;
interface CalendarInterface {
createCalendarEvent(name: string, location: string): void;
}
export default CalendarModule as CalendarInterface;

在其他 JavaScript 文件中,您可以像这样访问原生模块并调用其方法

tsx
import NativeCalendarModule from './NativeCalendarModule';
NativeCalendarModule.createCalendarEvent('foo', 'bar');

请注意,这假设您导入 CalendarModule 的位置与 NativeCalendarModule.js 位于相同的层级结构中。请根据需要更新相对导入。

参数类型

当在 JavaScript 中调用原生模块方法时,React Native 会将参数从 JS 对象转换为其 Objective-C/Swift 对象的对应物。因此,例如,如果您的 Objective-C 原生模块方法接受 NSNumber,在 JS 中您需要使用数字调用该方法。React Native 将为您处理转换。下面列出了原生模块方法支持的参数类型以及它们映射到的 JavaScript 等效项。

Objective-CJavaScript
NSString字符串,?字符串
BOOL布尔值
双精度浮点数数字
NSNumber?数字
NSArray数组,?数组
NSDictionary对象,?对象
RCTResponseSenderBlock函数(成功)
RCTResponseSenderBlock, RCTResponseErrorBlock函数(失败)
RCTPromiseResolveBlock, RCTPromiseRejectBlockPromise

以下类型目前受支持,但未来 TurboModules 将不支持。请避免使用它们。

  • 函数 (失败) -> RCTResponseErrorBlock
  • 数字 -> NSInteger
  • 数字 -> CGFloat
  • 数字 -> 浮点数

对于 iOS,您还可以使用 RCTConvert 类支持的任何参数类型编写原生模块方法(有关支持的详细信息,请参阅 RCTConvert)。RCTConvert 辅助函数都接受 JSON 值作为输入,并将其映射到原生 Objective-C 类型或类。

导出常量

原生模块可以通过重写原生方法 constantsToExport() 来导出常量。下面 constantsToExport() 被重写,并返回一个字典,其中包含一个您可以像这样在 JavaScript 中访问的默认事件名称属性

Objective-C
- (NSDictionary *)constantsToExport
{
return @{ @"DEFAULT_EVENT_NAME": @"New Event" };
}

然后可以通过在 JS 中调用原生模块上的 getConstants() 来访问常量,如下所示

tsx
const {DEFAULT_EVENT_NAME} = CalendarModule.getConstants();
console.log(DEFAULT_EVENT_NAME);

从技术上讲,可以直接从 NativeModule 对象访问 constantsToExport() 中导出的常量。TurboModules 将不再支持此功能,因此我们鼓励社区切换到上述方法,以避免将来的不必要迁移。

请注意,常量仅在初始化时导出,因此如果您在运行时更改 constantsToExport() 的值,它不会影响 JavaScript 环境。

对于 iOS,如果您重写 constantsToExport(),那么您还应该实现 + requiresMainQueueSetup,以告知 React Native 您的模块是否需要在主线程上初始化,在任何 JavaScript 代码执行之前。否则,您将看到一个警告,即您的模块将来可能会在后台线程上初始化,除非您明确选择使用 + requiresMainQueueSetup:。如果您的模块不需要访问 UIKit,那么您应该使用 NO 响应 + requiresMainQueueSetup

回调

原生模块还支持一种独特的参数——回调。回调用于将数据从 Objective-C 传递到 JavaScript,用于异步方法。它们也可以用于从原生端异步执行 JS。

对于 iOS,回调是使用 RCTResponseSenderBlock 类型实现的。下面,回调参数 myCallBack 被添加到 createCalendarEventMethod()

Objective-C
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title
location:(NSString *)location
myCallback:(RCTResponseSenderBlock)callback)

然后,您可以在原生函数中调用回调,在数组中提供您希望传递给 JavaScript 的任何结果。请注意,RCTResponseSenderBlock 只接受一个参数——一个要传递给 JavaScript 回调的参数数组。下面,您将返回在早期调用中创建的事件的 ID。

需要强调的是,回调不会在原生函数完成后立即调用——请记住通信是异步的。

Objective-C
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title location:(NSString *)location callback: (RCTResponseSenderBlock)callback)
{
NSInteger eventId = ...
callback(@[@(eventId)]);

RCTLogInfo(@"Pretending to create an event %@ at %@", title, location);
}

此方法可以通过以下方式在 JavaScript 中访问

tsx
const onSubmit = () => {
CalendarModule.createCalendarEvent(
'Party',
'04-12-2020',
eventId => {
console.log(`Created a new event with id ${eventId}`);
},
);
};

原生模块只应调用其回调一次。但是,它可以存储回调并稍后调用。这种模式通常用于封装需要委托的 iOS API——请参阅 RCTAlertManager 作为示例。如果回调从未被调用,则会发生内存泄漏。

回调有两种错误处理方法。第一种是遵循 Node 的约定,将传递给回调数组的第一个参数视为错误对象。

Objective-C
RCT_EXPORT_METHOD(createCalendarEventCallback:(NSString *)title location:(NSString *)location callback: (RCTResponseSenderBlock)callback)
{
NSNumber *eventId = [NSNumber numberWithInt:123];
callback(@[[NSNull null], eventId]);
}

在 JavaScript 中,您可以检查第一个参数以查看是否传递了错误

tsx
const onPress = () => {
CalendarModule.createCalendarEventCallback(
'testName',
'testLocation',
(error, eventId) => {
if (error) {
console.error(`Error found! ${error}`);
}
console.log(`event id ${eventId} returned`);
},
);
};

另一个选项是使用两个单独的回调:onFailure 和 onSuccess。

Objective-C
RCT_EXPORT_METHOD(createCalendarEventCallback:(NSString *)title
location:(NSString *)location
errorCallback: (RCTResponseSenderBlock)errorCallback
successCallback: (RCTResponseSenderBlock)successCallback)
{
@try {
NSNumber *eventId = [NSNumber numberWithInt:123];
successCallback(@[eventId]);
}

@catch ( NSException *e ) {
errorCallback(@[e]);
}
}

然后在 JavaScript 中,您可以为错误和成功响应添加单独的回调

tsx
const onPress = () => {
CalendarModule.createCalendarEventCallback(
'testName',
'testLocation',
error => {
console.error(`Error found! ${error}`);
},
eventId => {
console.log(`event id ${eventId} returned`);
},
);
};

如果您想将类似错误的对象传递给 JavaScript,请使用 RCTUtils.h 中的 RCTMakeError。目前,这只会将一个 Error 形状的字典传递给 JavaScript,但 React Native 旨在未来自动生成真正的 JavaScript Error 对象。您还可以提供 RCTResponseErrorBlock 参数,该参数用于错误回调并接受 NSError \* object。请注意,此参数类型将不被 TurboModules 支持。

Promise

原生模块也可以实现 Promise,这可以简化您的 JavaScript,尤其是在使用 ES2016 的 async/await 语法时。当原生模块方法的最后一个参数是 RCTPromiseResolveBlockRCTPromiseRejectBlock 时,其对应的 JS 方法将返回一个 JS Promise 对象。

将上述代码重构为使用 Promise 而不是回调,如下所示

Objective-C
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title
location:(NSString *)location
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSInteger eventId = createCalendarEvent();
if (eventId) {
resolve(@(eventId));
} else {
reject(@"event_failure", @"no event id returned", nil);
}
}

此方法的 JavaScript 对应部分返回一个 Promise。这意味着您可以在异步函数中使用 await 关键字来调用它并等待其结果

tsx
const onSubmit = async () => {
try {
const eventId = await CalendarModule.createCalendarEvent(
'Party',
'my house',
);
console.log(`Created a new event with id ${eventId}`);
} catch (e) {
console.error(e);
}
};

向 JavaScript 发送事件

原生模块可以向 JavaScript 发送事件,而无需直接调用。例如,您可能希望向 JavaScript 发送一个提醒,告知 iOS 日历应用程序中的日历事件即将发生。首选方法是子类化 RCTEventEmitter,实现 supportedEvents 并调用 self sendEventWithName

更新您的头文件类以导入 RCTEventEmitter 并子类化 RCTEventEmitter

Objective-C
//  CalendarModule.h

#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface CalendarModule : RCTEventEmitter <RCTBridgeModule>
@end

JavaScript 代码可以通过围绕您的模块创建一个新的 NativeEventEmitter 实例来订阅这些事件。

如果您在没有侦听器的情况下发出事件,则会收到警告,表示您不必要地消耗了资源。为了避免这种情况,并优化模块的工作负载(例如,通过取消订阅上游通知或暂停后台任务),您可以覆盖 RCTEventEmitter 子类中的 startObservingstopObserving

Objective-C
@implementation CalendarModule
{
bool hasListeners;
}

// Will be called when this module's first listener is added.
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}

// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}

- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
if (hasListeners) {// Only send events if anyone is listening
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
}

线程

除非原生模块提供自己的方法队列,否则它不应假定它是在哪个线程上调用的。目前,如果原生模块不提供方法队列,React Native 将为其创建一个单独的 GCD 队列并在其中调用其方法。请注意,这是一个实现细节,可能会发生变化。如果您想显式地为原生模块提供方法队列,请在原生模块中重写 (dispatch_queue_t) methodQueue 方法。例如,如果它需要使用仅限主线程的 iOS API,它应该通过以下方式指定:

Objective-C
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}

同样,如果操作可能需要很长时间才能完成,原生模块可以指定自己的队列来运行操作。同样,目前 React Native 将为您的原生模块提供一个单独的方法队列,但这是一个您不应依赖的实现细节。如果您不提供自己的方法队列,将来,您的原生模块的长时间运行操作可能会阻塞在其他不相关的原生模块上执行的异步调用。例如,这里的 RCTAsyncLocalStorage 模块创建了自己的队列,这样 React 队列就不会因等待可能缓慢的磁盘访问而被阻塞。

Objective-C
- (dispatch_queue_t)methodQueue
{
return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
}

指定的 methodQueue 将由模块中的所有方法共享。如果您的方法中只有一个长时间运行(或由于某种原因需要在与其它方法不同的队列上运行),您可以在方法内部使用 dispatch_async 来在另一个队列上执行该特定方法的代码,而不会影响其他方法

Objective-C
RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Call long-running code on background thread
...
// You can invoke callback from any thread/queue
callback(@[...]);
});
}

模块间共享调度队列

methodQueue 方法将在模块初始化时被调用一次,然后由 React Native 保留,因此除非您希望在模块中使用它,否则无需自己保留对队列的引用。但是,如果您希望在多个模块之间共享同一个队列,则需要确保您保留并返回它们中每一个的相同队列实例。

依赖注入

React Native 将自动创建和初始化任何已注册的原生模块。但是,您可能希望创建和初始化自己的模块实例,例如,注入依赖项。

您可以通过创建一个实现 RCTBridgeDelegate 协议的类,使用委托作为参数初始化一个 RCTBridge,并使用已初始化的桥接初始化一个 RCTRootView 来实现。

Objective-C
id<RCTBridgeDelegate> moduleInitialiser = [[classThatImplementsRCTBridgeDelegate alloc] init];

RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil];

RCTRootView *rootView = [[RCTRootView alloc]
initWithBridge:bridge
moduleName:kModuleName
initialProperties:nil];

导出 Swift

Swift 不支持宏,因此将原生模块及其方法暴露给 React Native 中的 JavaScript 需要更多的设置。但是,它的工作原理相对相同。假设您有相同的 CalendarModule,但它是一个 Swift 类

Swift
// CalendarModule.swift

@objc(CalendarModule)
class CalendarModule: NSObject {

@objc(addEvent:location:date:)
func addEvent(_ name: String, location: String, date: NSNumber) -> Void {
// Date is ready to use!
}

@objc
func constantsToExport() -> [String: Any]! {
return ["someKey": "someValue"]
}

}

使用 @objc 修饰符非常重要,以确保类和函数正确导出到 Objective-C 运行时。

然后创建一个私有实现文件,它将向 React Native 注册所需的信息

Objective-C
// CalendarModuleBridge.m
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(CalendarModule, NSObject)

RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)

@end

对于 Swift 和 Objective-C 的新手来说,无论何时您在 iOS 项目中混合使用这两种语言,您还需要一个额外的桥接文件,称为桥接头文件,以将 Objective-C 文件暴露给 Swift。如果您通过 Xcode 的 文件 > 新文件 菜单选项将 Swift 文件添加到您的应用程序中,Xcode 将会为您创建此头文件。您需要在该头文件中导入 RCTBridgeModule.h

Objective-C
// CalendarModule-Bridging-Header.h
#import <React/RCTBridgeModule.h>

您还可以使用 RCT_EXTERN_REMAP_MODULE_RCT_EXTERN_REMAP_METHOD 来更改您正在导出的模块或方法的 JavaScript 名称。欲了解更多信息,请参阅 RCTBridgeModule

制作第三方模块时请注意:静态库与 Swift 仅在 Xcode 9 及更高版本中受支持。为了在您的模块中包含的 iOS 静态库中使用 Swift 时 Xcode 项目能够构建,您的主应用程序项目必须包含 Swift 代码和桥接头文件本身。如果您的应用程序项目不包含任何 Swift 代码,解决方法可以是单个空的 .swift 文件和空的桥接头文件。

保留方法名称

invalidate()

原生模块可以通过在 iOS 上实现 invalidate() 方法来遵循 RCTInvalidating 协议。当原生桥接被失效时(即:在开发模式重新加载时),可以调用此方法。请根据需要使用此机制对您的原生模块进行必要的清理。