代码生成器
本文档仍为 experimental,详细信息可能会随着我们的迭代而发生变化。 欢迎在此页面分享你对 工作组内部讨论 的反馈。
英This documentation is still experimental and details are subject to changes as we iterate. Feel free to share your feedback on the discussion inside the working group for this page.
而且,它还包含几个 手动步骤。 请注意,一旦新架构稳定,这将不代表最终的开发者体验。 我们正在开发工具、模板和库,以帮助你快速开始使用新架构,而无需完成整个设置。
英Moreover, it contains several manual steps. Please note that this won't be representative of the final developer experience once the New Architecture is stable. We're working on tools, templates and libraries to help you get started fast on the New Architecture, without having to go through the whole setup.
代码生成器 并不是一个真正的支柱,但它是一个可以用来避免编写大量重复代码的工具。 使用 代码生成器 不是强制的: 它生成的所有代码也可以手动编写。 但是,它生成的脚手架代码可以为你节省大量时间。
英The Codegen is not a proper pillar, but it is a tool that can be used to avoid writing a lot of repetitive code. Using Codegen is not mandatory: all the code that is generated by it can also be written manually. However, it generates scaffolding code that could save you a lot of time.
每次构建 iOS 或 Android 应用时,React Native 都会自动调用 代码生成器。 有时,你希望运行手动生成代码的脚本来了解实际生成了哪些类型和文件: 例如,这是开发 Turbo Native 模块 和 Fabric 原生组件 时的常见情况。
英The Codegen is invoked automatically by React Native every time an iOS or Android app is built. Occasionally, you would like to run the scripts that generate the code manually to know which types and files are actually generated: this is a common scenario when developing Turbo Native Modules and Fabric Native Components, for example.
本指南介绍如何配置 代码生成器,以及如何为每个平台手动调用它,并描述生成的代码。
英This guide teaches how to configure the Codegen, and how to invoke it manually for each platform, and describes the generated code.
先决条件
即使手动调用 代码生成器,你始终需要一个 React Native 应用来正确生成代码。
英You always need a React Native app to generate the code properly, even when invoking the Codegen manually.
代码生成器 进程与应用的构建紧密耦合,脚本位于 react-native
NPM 包中。
英The Codegen process is tightly coupled with the build of the app, and the scripts are located in the react-native
NPM package.
为了本指南的目的,请使用 React Native CLI 创建一个项目,如下所示:
英For the sake of this guide, create a project using the React Native CLI as follows:
npx react-native init SampleApp --version 0.70.0
本指南假设使用的 React Native 版本为 0.70.0 或更高版本。 以前版本的 React Native 使用 代码生成器 版本,需要稍微不同的设置。
然后,添加需要 代码生成器 的模块作为应用的 NPM 依赖:
英Then, add the module that requires the Codegen as an NPM dependency of the app:
yarn add <path/to/your/TurboNativeModule_or_FabricNativeComponent>
请参阅如何创建 Turbo Native 模块 或 Fabric 原生组件 以获取有关如何配置它们的更多信息。
英See how to create a Turbo Native Module or a Fabric Native Component to get more information on how to configure them.
本指南的其余部分假设你已正确设置 Turbo Native Module
和/或 Fabric Native Component
。
英The rest of this guide assumes that you have a Turbo Native Module
and/or a Fabric Native Component
properly set up.
iOS
运行代码生成器
iOS 的 代码生成器 依赖于在构建过程中调用的一些 Node 脚本。 这些脚本位于 MyApp/node_modules/react-native/scripts/
文件夹中。
英The Codegen for iOS relies on some Node scripts that are invoked during the build process. The scripts are located in the MyApp/node_modules/react-native/scripts/
folder.
你必须运行的脚本是 generate-codegen-artifacts.js
脚本。 这会在应用的所有依赖中进行搜索,查找遵循某些特定约定的 JS 文件(有关详细信息,请参阅 TurboModules 和 Fabric 组件 部分),并生成所需的代码。
英The script that you have to run is the generate-codegen-artifacts.js
script. This searches among all the dependencies of the app, looking for JS files that respects some specific conventions (look at TurboModules and Fabric Components sections for details), and it generates the required code.
要调用该脚本,你可以从应用的根文件夹运行以下命令:
英To invoke the script, you can run this command from the root folder of your app:
node node_modules/react-native/scripts/generate-codegen-artifacts.js \
--path SampleApp/ \
--outputPath <an/output/path> \
鉴于应用已将 Turbo Native Modules
和/或 Fabric Native Components
配置为依赖,代码生成器 会查找所有这些并在你提供的路径中生成代码。
英Given that the app has Turbo Native Modules
and/or Fabric Native Components
configured as a dependency, Codegen looks for all of them and generates the code in the path you provided.
生成的代码
例如,如果你在应用中运行 代码生成器,输出路径为 codegen
,你将获得以下结构:
英If you run the Codegen in your app with an output path of codegen
, for example, you obtain the following structure:
codegen
└── build
└── generated
└── ios
├── MyTurboModuleSpecs
│ ├── MyTurboModuleSpecs-generated.mm
│ └── MyTurboModuleSpecs.h
├── FBReactNativeSpec
│ ├── FBReactNativeSpec-generated.mm
│ └── FBReactNativeSpec.h
├── RCTThirdPartyFabricComponentsProvider.h
├── RCTThirdPartyFabricComponentsProvider.mm
└── react
└── renderer
└── components
├── MyFabricComponent
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── RCTComponentViewHelpers.h
│ ├── ShadowNodes.cpp
│ └── ShadowNodes.h
└── rncore
├── ComponentDescriptors.h
├── EventEmitters.cpp
├── EventEmitters.h
├── Props.cpp
├── Props.h
├── RCTComponentViewHelpers.h
├── ShadowNodes.cpp
└── ShadowNodes.h
正如预期的那样,codegen
文件夹位于层次结构的根部。 其中嵌套了另外两个文件夹: build/generated
。
英The codegen
folder sits at the root of the hierarchy, as expected. Nested into it, there are two more folders: build/generated
.
然后,有一个 ios
文件夹,其中包含:
英Then, there is an ios
folder that contains:
- 每个 TurboModule 的自定义文件夹。
RCTThirdPartyFabricComponentsProvider
的标头 (.h
) 和实现 (.mm
) 文件。- 基本
react/renderer/components
文件夹,其中包含每个Fabric Native Component
的自定义文件夹。
在上面的示例中,同时存在一个 TurboModule 和一组 Fabric Native 组件。 这些是由 React Native 本身生成的: FBReactNativeSpec
和 rncore
。 即使你没有任何额外的 TurboModule 或 Fabric Native 组件,这些模块也将始终出现: React Native 需要它们才能正常工作。
英In the example above, there are both a TurboModule and a set of Fabric Native Components. These are generated by React Native itself: FBReactNativeSpec
and rncore
. These modules will always appear even if you don't have any extra TurboModule or Fabric Native Component: React Native requires them in order to work properly.
Turbo Native 模块
每个文件夹包含两个文件: 接口文件和实现文件。
英Each folder contains two files: an interface file and an implementation file.
接口文件与 Turbo Native Module 具有相同的名称,并包含初始化 JSI 接口的方法。
英The interface files have the same name as that of the Turbo Native Module and contain methods to initialize the JSI interface.
相反,实现文件具有 -generated
后缀,并包含从 JS 调用原生方法的逻辑,反之亦然。
英The implementation files, instead, have the -generated
suffix and contain the logic to invoke the native methods from JS and vice-versa.
Fabric 原生组件
每个 Fabric Native Component 文件夹的内容都包含多个文件。 Fabric Native 组件的基本元素是 ShadowNode
: 它代表 React 抽象树中的一个节点。 ShadowNode
代表一个 React 实体; 因此,它可能需要一些在 Props
文件中定义的 props,有时还需要在相应文件中定义的 EventEmitter
。
英The content of each Fabric Native Component folder contains several files. The basic element for a Fabric Native Component is the ShadowNode
: it represents a node in the React abstract tree. The ShadowNode
represents a React entity; therefore, it could need some props, which are defined in the Props
files and, sometimes, an EventEmitter
, defined in the corresponding file.
此外,代码生成器 还创建 ComponentDescriptor.h
和 RCTComponentViewHelpers.h
文件: 第一个由 React Native 和 Fabric 使用来正确获取对 Fabric Native 组件的引用,而后者包含一些可以由 Native View 实现的帮助方法和协议,以正确响应 JSI 调用。
英Additionally, the Codegen also creates a ComponentDescriptor.h
and an RCTComponentViewHelpers.h
files: the first one is used by React Native and Fabric to properly get a reference to the Fabric Native Component, while the latter contains some helper methods and protocols that can be implemented by the Native View to properly respond to JSI invocations.
有关 Fabric 工作原理的更多详细信息,请查看 渲染器 部分。
英For further details about how Fabric works, have a look at the Renderer section.
RCTThirdPartyFabricComponentsProvider
这些是注册表的接口和实现文件。 React Native 在运行时使用此注册表来检索所需 Fabric Native 组件的正确类。 一旦 React Native 有了该类的句柄,它就可以实例化它。
英These are interface and implementation files for a registry. React Native uses this registry at runtime to retrieve the right class for a required Fabric Native Component. Once React Native has a handle to that class, it can instantiate it.
安卓
运行代码生成器
Android Codegen
依赖 Gradle 任务来生成所需的代码。 首先,你需要配置 Android 应用以使用新架构; 否则,Gradle 任务将失败。
英Android Codegen
relies on a Gradle task to generate the required code. First, you need to configure the Android app to work with the New Architecture; otherwise, the Gradle task fails.
- 打开
MyApp/android/gradle.properties
文件。 - 将
newArchEnabled
标志从false
翻转到true
。
之后,你可以导航到 SampleApp/android
文件夹并运行:
英After that, you can navigate into the SampleApp/android
folder and run:
./gradlew generateCodegenArtifactsFromSchema
这些任务在应用的所有导入项目(应用和链接到它的所有节点模块)上调用 generateCodegenArtifactsFromSchema
。 它会在相应的 node_modules/<dependency>
文件夹中生成代码。 因此,例如,如果你有一个 Fabric Native 组件,其节点模块名为 my-fabric-component
,则生成的代码位于 SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen
路径中。
英These tasks invoke the generateCodegenArtifactsFromSchema
on all the the imported projects of the app (the app and all the node modules which are linked to it). It generates the code in the corresponding node_modules/<dependency>
folder. So, for example, if you have a Fabric Native Component whose node module is called my-fabric-component
, the generated code is located in the SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen
path.
生成的代码
Gradle 任务完成后,你可以看到 Turbo Native 模块或 Fabric Native 组件的不同结构。 以下选项卡显示了它们的显示方式:
英Once the Gradle task completes, you can see different structures for a Turbo Native Module or for a Fabric Native Component. The following tab shows how they appear:
- turbomodules
- fabric-components
codegen
├── java
│ └── com
│ └── MyTurbomodule
│ └── MyTurbomodule.java
├── jni
│ ├── Android.mk
│ ├── CMakeLists.txt
│ ├── MyTurbomodule-generated.cpp
│ ├── MyTurbomodule.h
│ └── react
│ └── renderer
│ └── components
│ └── MyTurbomodule
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── ShadowNodes.cpp
│ └── ShadowNodes.h
└── schema.json
codegen
├── java
│ └── com
│ └── facebook
│ └── react
│ └── viewmanagers
│ ├── MyFabricComponentManagerDelegate.java
│ └── MyFabricComponentManagerInterface.java
├── jni
│ ├── Android.mk
│ ├── CMakeLists.txt
│ ├── MyFabricComponent-generated.cpp
│ ├── MyFabricComponent.h
│ └── react
│ └── renderer
│ └── components
│ └── MyFabricComponent
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── ShadowNodes.cpp
│ └── ShadowNodes.h
└── schema.json
Java 无法像 Objective-C++ 那样与 C++ 无缝互操作。 为了正常工作,代码生成器 在定义 Java 原生接口的 jni
文件夹中创建了 Java 和 C++ 世界之间的一些桥接。
英Java can't interoperate seamlessly with C++ as Objective-C++ does. To work properly, Codegen creates some bridging between the Java and the C++ world in the jni
folder, where the Java Native Interfaces are defined.
请注意,Turbo Native 模块和 Fabric Native 组件都带有两个构建文件描述符: Android.mk
和 CMakeLists.txt
。 Android 应用使用它们来实际构建外部模块。
英Notice that both Turbo Native Modules and Fabric Native Components come with two build file descriptors: the Android.mk
and the CMakeLists.txt
. These are used by the Android app to actually build the external modules.
Turbo Native 模块
代码生成器 在 java
包中生成一个与 TurboModule 同名的 Java 抽象类。 这个抽象类必须由 JNI C++ 实现来实现。
英The Codegen generates a Java abstract class in the java
package with the same name as that of the TurboModule. This abstract class has to be implemented by the JNI C++ implementation.
然后,它在 jni
文件夹中生成 C++ 文件。 它们遵循相同的 iOS 约定: 有一个名为 MyTurbomodule.h
的接口和一个名为 MyTurbomodule-generated.cpp
的实现文件。 前者是一个接口,允许 React Native 为 TurboModule 初始化 JSI 接口。 后者是实现文件,其中包含从 JS 调用原生方法的逻辑,反之亦然。
英Then, it generates the C++ files in the jni
folder. They follow the same iOS convention: there is an interface called MyTurbomodule.h
and an implementation file called MyTurbomodule-generated.cpp
. The former is an interface that allows React Native to initialize the JSI interface for the TurboModule. The latter is the implementation file which contains the logic to invoke the native method from JS and vice-versa.
Fabric 原生组件
Fabric Native 组件的 代码生成器 在 java
包中包含 MyFabricComponentManagerInterface.java
和 MyFabricComponentManagerDelegate.java
。 它们由在运行时正确加载组件所需的原生 MyFabricComponentManager
实现和使用(有关详细信息,请参阅有关如何创建 Fabric 原生组件 的指南)。
英The Codegen for a Fabric Native Component contains a MyFabricComponentManagerInterface.java
and a MyFabricComponentManagerDelegate.java
in the java
package. They are implemented and used by the native MyFabricComponentManager
required to properly load the component at runtime (See the guide on how to create a Fabric Native Component for details).
然后,还有一层 JNI C++ 文件,Fabric 使用它们来渲染组件。 Fabric 组件的基本元素是 ShadowNode
: 它代表 React 抽象树中的一个节点。 ShadowNode
代表一个 React 实体; 因此它可能需要一些在 Props
文件中定义的 props,有时还需要在相应文件中定义的 EventEmitter
。
英Then, there is a layer of JNI C++ files that are used by Fabric to render the components. The basic element for a Fabric Component is the ShadowNode
: it represents a node in the React abstract tree. The ShadowNode
represents a React entity; therefore it could need some props, which are defined in the Props
files and, sometimes, an EventEmitter
, defined in the corresponding file.
代码生成器 还创建了 ComponentDescriptor.h
,这是获得 Fabric 原生组件的正确处理所必需的。
英The Codegen also creates a ComponentDescriptor.h
, which is required to get a proper handle on the Fabric Native Component.