使用 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 Modules 和 Fabric Native Components 的指南。
設定 Codegen
可以在您的應用程式中透過修改 package.json
檔案來設定 Codegen。 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>"
},
}
},
您可以將此程式碼片段新增到您的應用程式並自訂各種欄位
name:
這是將用於建立包含您的規格檔案的名稱。 按照慣例,它應該具有Spec
後綴,但這不是強制性的。type
: 我們需要生成的程式碼類型。 允許的值為modules
、components
、all
。modules:
如果您只需要為 Turbo Native Modules 生成程式碼,請使用此值。components:
如果您只需要為 Native Fabric 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
)。
當 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 Plugin (RNGP) 整合。 RNGP 包含一個可以調用的任務,該任務會讀取在 package.json
檔案中定義的配置並執行 Codegen。 若要執行 gradle 任務,請先導覽至專案的 android
資料夾內。 然後執行
./gradlew generateCodegenArtifactsFromSchema
此任務會在應用程式的所有匯入專案(應用程式和所有連結到它的節點模組)上調用 generateCodegenArtifactsFromSchema
命令。 它會在對應的 node_modules/<dependency>
資料夾中生成程式碼。 例如,如果您有一個 Node 模組名為 my-fabric-component
的 Fabric Native 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 在 Core 中使用。 然後有一組檔案,其中包含您在 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
,則預期看不到任何其他檔案。