使用 Codegen
本指南将教你如何:
- 配置 Codegen。
 - 手动为每个平台调用它。
 
它还描述了生成的代码。
前提条件
你总是需要一个 React Native 应用来正确生成代码,即使手动调用 Codegen。
Codegen 过程与应用的构建紧密耦合,脚本位于 react-native NPM 包中。
为了本指南,创建一个使用 React Native CLI 的项目,如下所示:
npx @react-native-community/cli@latest init SampleApp --version 0.76.0
Codegen 用于生成自定义模块或组件的粘合代码。有关如何创建它们的更多详细信息,请参阅 Turbo Native 模块和 Fabric Native 组件的指南。
配置 Codegen
你可以通过修改 package.json 文件来配置 Codegen。Codegen 由一个名为 codegenConfig 的自定义字段控制。
  "codegenConfig": {
    "name": "<SpecName>",
    "type": "<types>",
    "jsSrcsDir": "<source_dir>",
    "android": {
      "javaPackageName": "<java.package.name>"
    }
  },
你可以将此片段添加到你的应用中,并自定义各个字段:
name:这是用于创建包含规范的文件的名称。按照惯例,它应该有后缀Spec,但这不是必须的。type: 我们需要生成的代码类型。允许的值是modules,components,all。modules:如果你只需要为 Turbo 原生模块生成代码,请使用此值。components:如果你只需要为原生 Fabric 组件生成代码,请使用此值。all: 如果你有组件和模块的混合,请使用此值。
jsSrcsDir: 这是所有规范所在的根文件夹。android.javaPackageName: 这是 Android 特有的设置,让 Codegen 在自定义包中生成文件。
当 Codegen 运行时,它会在应用的所有依赖项中搜索遵循某些特定约定的 JS 文件,并生成所需的代码:
- Turbo 原生模块要求规范文件以 
Native开头。例如,NativeLocalStorage.ts是一个有效的规范文件名。 - 原生 Fabric 组件要求规范文件以 
NativeComponent结尾。例如,WebViewNativeComponent.tx是一个有效的规范文件名。 
运行 Codegen
本指南的其余部分假设你已经在项目中设置了一个原生 Turbo 模块、一个原生 Fabric 组件或两者都有。我们还假设你已经在 package.json 中指定了 jsSrcsDir 的有效规范文件。
Android
Android 的 Codegen 与 React Native Gradle 插件(RNGP)集成。RNGP 包含一个可以调用的任务,该任务读取 package.json 文件中定义的配置并执行 Codegen。要运行 gradle 任务,首先导航到项目的 android 文件夹。然后运行:
./gradlew generateCodegenArtifactsFromSchema
此任务调用 generateCodegenArtifactsFromSchema 命令,该命令在应用的所有导入项目(应用和所有链接到它的节点模块)中执行。生成的代码位于相应的 node_modules/<dependency> 文件夹中。例如,如果你有一个原生 Fabric 组件,其节点模块名为 my-fabric-component,生成的代码位于 SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen 路径。对于应用,代码生成在 android/app/build/generated/source/codegen 文件夹中。
生成的代码
运行上述 gradle 命令后,你将在 SampleApp/android/app/build 文件夹中找到 Codegen 代码。结构将如下所示:
build
└── generated
    └── source
        └── codegen
            ├── java
            │   └── com
            │       ├── facebook
            │       │   └── react
            │       │       └── viewmanagers
            │       │           ├── <nativeComponent>ManagerDelegate.java
            │       │           └── <nativeComponent>ManagerInterface.java
            │       └── sampleapp
            │           └── NativeLocalStorageSpec.java
            ├── jni
            │   ├── <codegenConfig.name>-generated.cpp
            │   ├── <codegenConfig.name>.h
            │   ├── CMakeLists.txt
            │   └── react
            │       └── renderer
            │           └── components
            │               └── <codegenConfig.name>
            │                   ├── <codegenConfig.name>JSI-generated.cpp
            │                   ├── <codegenConfig.name>.h
            │                   ├── ComponentDescriptors.cpp
            │                   ├── ComponentDescriptors.h
            │                   ├── EventEmitters.cpp
            │                   ├── EventEmitters.h
            │                   ├── Props.cpp
            │                   ├── Props.h
            │                   ├── ShadowNodes.cpp
            │                   ├── ShadowNodes.h
            │                   ├── States.cpp
            │                   └── States.h
            └── schema.json
生成的代码分为两个文件夹:
java包含平台特定的代码jni包含 C++ 代码,以让 JS 和 Java 正确交互。
在 java 文件夹中,你可以找到原生 Fabric 组件生成的代码,位于 com/facebook/viewmanagers 子文件夹中。
<nativeComponent>ManagerDelegate.java包含ViewManager可以调用的方法。<nativeComponent>ManagerInterface.java包含ViewManager的接口。
在 jni 文件夹中,最后是所有连接 JS 和 Android 的样板代码。
<codegenConfig.name>.hthis contains the interface of your custom C++ Turbo Native Modules.<codegenConfig.name>-generated.cpp包含自定义 C++ Turbo 原生模块的粘合代码。react/renderer/components/<codegenConfig.name>: 包含自定义组件所需的粘合代码。
此结构是通过使用 codegenConfig.type 字段的值 all 生成的。如果你使用 modules 值,期望看不到 react/renderer/components/ 文件夹。如果你使用 components 值,期望看不到其他文件。
iOS
iOS 的 Codegen 依赖于一些在构建过程中调用的 Node 脚本。这些脚本位于 SampleApp/node_modules/react-native/scripts/ 文件夹中。
主脚本是 generate-Codegen-artifacts.js 脚本。要调用该脚本,可以从应用的根文件夹运行以下命令:
node node_modules/react-native/scripts/generate-Codegen-artifacts.js \
    --path <path/to/your/app> \
    --outputPath <an/output/path> \
    --targetPlatform <android | ios>
其中:
--path是应用根文件夹的路径。--outputPath是 Codegen 写入生成文件的目标路径。--targetPlatform是你希望生成代码的平台。
生成的代码
使用这些参数来运行:
node node_modules/react-native/scripts/generate-Codegen-artifacts.js \
    --path . \
    --outputPath ios/ \
    --targetPlatform ios
将在 ios/build 文件夹中生成这些文件:
build
└── generated
    └── ios
        ├── <codegenConfig.name>
        │   ├── <codegenConfig.name>-generated.mm
        │   └── <codegenConfig.name>.h
        ├── <codegenConfig.name>JSI-generated.cpp
        ├── <codegenConfig.name>JSI.h
        ├── FBReactNativeSpec
        │   ├── FBReactNativeSpec-generated.mm
        │   └── FBReactNativeSpec.h
        ├── FBReactNativeSpecJSI-generated.cpp
        ├── FBReactNativeSpecJSI.h
        ├── RCTModulesConformingToProtocolsProvider.h
        ├── RCTModulesConformingToProtocolsProvider.mm
        └── react
            └── renderer
                └── components
                    └── <codegenConfig.name>
                        ├── ComponentDescriptors.cpp
                        ├── ComponentDescriptors.h
                        ├── EventEmitters.cpp
                        ├── EventEmitters.h
                        ├── Props.cpp
                        ├── Props.h
                        ├── RCTComponentViewHelpers.h
                        ├── ShadowNodes.cpp
                        ├── ShadowNodes.h
                        ├── States.cpp
                        └── States.h
这些生成的文件中的一部分被 React Native 核心使用。然后有一组文件,其名称与你在 package.json 中指定的 codegenConfig.name 字段相同。
<codegenConfig.name>/<codegenConfig.name>.h: 包含自定义 iOS Turbo 原生模块的接口。<codegenConfig.name>/<codegenConfig.name>-generated.mm: 包含自定义 iOS Turbo 原生模块的粘合代码。<codegenConfig.name>JSI.h: 包含自定义 C++ Turbo 原生模块的接口。<codegenConfig.name>JSI-generated.h: 包含自定义 C++ Turbo 原生模块的粘合代码。react/renderer/components/<codegenConfig.name>: 此文件夹包含自定义组件所需的粘合代码。
此结构是通过使用 codegenConfig.type 字段的值 all 生成的。如果你使用 modules 值,期望看不到 react/renderer/components/ 文件夹。如果你使用 components 值,期望看不到其他文件。