使用 Codegen
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
本指南将教你如何:
-
配置 Codegen
-
为各平台手动调用 Codegen
同时介绍生成的代码结构
准备工作
即使手动调用 Codegen,你也必须拥有一个 React Native 应用才能正确生成代码。
Codegen 流程与应用构建紧密关联,相关脚本位于 react-native NPM 包中。
为便于演示,请使用 React Native CLI 创建项目:
npx @react-native-community/cli@latest init SampleApp --version 0.76.0
Codegen 用于为自定义模块或组件生成粘合代码。有关创建方法,请参阅 Turbo Native Modules 和 Fabric Native Components 指南。
配置 Codegen
可通过修改 package.json 文件配置 Codegen,其行为由名为 codegenConfig 的自定义字段控制。
"codegenConfig": {
"name": "<SpecName>",
"type": "<types>",
"jsSrcsDir": "<source_dir>",
"android": {
"javaPackageName": "<java.package.name>"
},
"ios": {
"modulesConformingToProtocol": {
"RCTImageURLLoader": [
"<iOS-class-conforming-to-RCTImageURLLoader>",
// example from react-native-camera-roll: https://github.com/react-native-cameraroll/react-native-cameraroll/blob/8a6d1b4279c76e5682a4b443e7a4e111e774ec0a/package.json#L118-L127
// "RNCPHAssetLoader",
],
"RCTURLRequestHandler": [
"<iOS-class-conforming-to-RCTURLRequestHandler>",
// example from react-native-camera-roll: https://github.com/react-native-cameraroll/react-native-cameraroll/blob/8a6d1b4279c76e5682a4b443e7a4e111e774ec0a/package.json#L118-L127
// "RNCPHAssetUploader",
],
"RCTImageDataDecoder": [
"<iOS-class-conforming-to-RCTImageDataDecoder>",
// we don't have a good example for this, but it works in the same way. Pass the name of the class that implements the RCTImageDataDecoder. It must be a Native Module.
]
},
"componentProvider": {
"<componentName>": "<iOS-class-implementing-the-component>"
},
"modulesProvider": {
"<moduleName>": "<iOS-class-implementing-the-RCTModuleProvider-protocol>"
}
}
},
将以下代码片段添加到应用中并自定义各字段:
-
name::用于创建规范文件的名称。按惯例应包含Spec后缀,但非强制要求。 -
type:需生成的代码类型,可选值:modules、components、allmodules::仅需为 Turbo Native Modules 生成代码时使用components::仅需为 Fabric Native Components 生成代码时使用all:同时包含模块和组件时使用
-
jsSrcsDir:所有规范文件的根目录路径 -
android.javaPackageName:Android 专属设置,用于指定 Codegen 生成文件的包名 -
ios:ios字段是一个对象,应用开发者和库维护者可通过它提供高级功能。以下所有字段均为可选:ios.modulesConformingToProtocol: React Native 提供了一些协议,原生模块可通过实现这些协议自定义行为。此字段用于定义符合特定协议的模块列表,这些模块将在应用启动时注入 React Native 运行时:ios.modulesConformingToProtocol.RCTImageURLLoader: 实现RCTImageURLLoader协议 的 iOS 原生模块列表。需传入实现RCTImageURLLoader的 iOS 类名,且必须是原生模块。ios.modulesConformingToProtocol.RCTURLRequestHandler: 实现RCTURLRequestHandler协议 的 iOS 原生模块列表。需传入实现RCTURLRequestHandler的 iOS 类名,且必须是原生模块。ios.modulesConformingToProtocol.RCTImageDataDecoder: 实现RCTImageDataDecoder协议 的 iOS 原生模块列表。需传入实现RCTImageDataDecoder的 iOS 类名,且必须是原生模块。
ios.componentProvider: 此字段是映射表,用于生成自定义 JS React 组件与原生实现类的关联。映射键为组件 JS 名称(如TextInput),值为实现组件的 iOS 类(如RCTTextInput)。ios.modulesProvider: 此字段是映射表,用于生成自定义 JS 原生模块与其提供者原生类的关联。映射键为模块 JS 名称(如NativeLocalStorage),值为实现RCTModuleProvider协议 的 iOS 类。Objective-C 模块中,实现RCTTurboModule协议 的类也实现了RCTModuleProvider协议。更多细节请参阅跨平台原生模块(C++)指南。
当 Codegen 运行时,它会在应用的所有依赖中搜索符合特定约定的 JS 文件,并生成所需的代码:
-
Turbo Native Modules 要求规范文件以
Native为前缀。例如,NativeLocalStorage.ts是有效的规范文件名。 -
Native Fabric Components 要求规范文件以
NativeComponent为后缀。例如,WebViewNativeComponent.ts是有效的规范文件名。
运行 Codegen
本指南剩余部分假设你已在项目中设置好 Native Turbo Module、Native Fabric Component 或两者兼备。同时假设你在 package.json 指定的 jsSrcsDir 目录中存在有效的规范文件。
Android 相关
Android 的 Codegen 已与 React Native Gradle 插件 (RNGP) 集成。RNGP 包含一个可调用的任务,该任务会读取 package.json 中定义的配置并执行 Codegen。要运行此 gradle 任务,请先进入项目的 android 文件夹,然后执行:
./gradlew generateCodegenArtifactsFromSchema
此任务会在应用的所有导入项目(应用本身及其所有链接的 node 模块)上调用 generateCodegenArtifactsFromSchema 命令。生成的代码位于相应的 node_modules/<dependency> 文件夹中。例如,如果你的 Fabric Native Component 对应的 Node 模块名为 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:包含确保 JS 与 Java 正确交互所需的 C++ 代码
在 java 文件夹中,你可以在 com/facebook/viewmanagers 子目录找到 Fabric Native Component 的生成代码:
-
<nativeComponent>ManagerDelegate.java包含ViewManager可在自定义 Native Component 上调用的方法 -
<nativeComponent>ManagerInterface.java包含ViewManager的接口
在 codegenConfig.android.javaPackageName 指定的文件夹中,你可以找到 Turbo Native Module 为实现其功能而需继承的抽象类。
最后在 jni 文件夹中,包含了连接 JS 与 Android 的所有样板代码:
-
<codegenConfig.name>.h:包含自定义 C++ Turbo Native Modules 的接口 -
<codegenConfig.name>-generated.cpp:包含自定义 C++ Turbo Native Modules 的胶水代码 -
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
Usage: generate-codegen-artifacts.js -p [path to app] -t [target platform] -o [output path]
Options:
--help Show help [boolean]
--version Show version number [boolean]
-p, --path Path to the React Native project root. [required]
-t, --targetPlatform Target platform. Supported values: "android", "ios",
"all". [required]
-o, --outputPath Path where generated artifacts will be output to.
其中:
-
--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 Native Modules 的接口声明 -
<codegenConfig.name>/<codegenConfig.name>-generated.mm:包含自定义 iOS Turbo Native Modules 的胶水代码 -
<codegenConfig.name>JSI.h:包含自定义 C++ Turbo Native Modules 的接口声明 -
<codegenConfig.name>JSI-generated.h:包含自定义 C++ Turbo Native Modules 的胶水代码 -
react/renderer/components/<codegenConfig.name>:该目录包含自定义组件所需的所有胶水代码
此文件结构基于 codegenConfig.type 字段设为 all 时生成。若设为 modules 则不会生成 react/renderer/components/ 目录;若设为 components 则不会生成其他类型文件。