Turbo Native 模块
本文档仍为 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.
如果你使用过 React Native,你可能熟悉 原生模块 的概念,它允许 JavaScript 和平台原生代码通过 React Native "bridge" 进行通信,后者通过 JSON 处理跨平台序列化。
英If you've worked with React Native, you may be familiar with the concept of Native Modules, which allow JavaScript and platform-native code to communicate over the React Native "bridge", which handles cross-platform serialization via JSON.
Turbo Native Modules 是 Native Modules 的下一代迭代,提供了一些额外的 benefits:
英Turbo Native Modules are the next iteration on Native Modules that provide a few extra benefits:
- 跨平台一致的强类型接口
- 能够用 C++ 编写代码,无论是单独的还是与其他原生平台语言集成,从而减少跨平台重复实现的需要
- 模块的延迟加载,允许更快的应用启动
- 使用 JSI(原生代码的 JavaScript 接口)可以比桥接器更有效地在原生和 JavaScript 代码之间进行通信
本指南将向你展示如何创建与最新版本的 React Native 兼容的基本 Turbo Native 模块。
英This guide will show you how to create a basic Turbo Native Module compatible with the latest version of React Native.
Turbo Native 模块仅适用于启用 新架构 的情况。 要迁移到 新架构,请按照 迁移指南 操作:::
如何创建 Turbo Native 模块
要创建 Turbo Native 模块,我们需要:
英To create a Turbo Native Module, we need to:
- 定义 JavaScript 规范。
- 配置模块,以便 Codegen 可以生成脚手架。
- 编写原生代码完成模块的实现。
1. 文件夹设置
为了使模块与应用解耦,最好将模块与应用分开定义,然后将其作为依赖添加到应用中。 这也是你编写 Turbo Native 模块所需要做的事情,这些模块稍后可以作为开源库发布。
英In order to keep the module decoupled from the app, it's a good idea to define the module separately from the app and then add it as a dependency to your app later. This is also what you'll do for writing Turbo Native Modules that can be released as open-source libraries later.
在你的应用旁边,创建一个名为 RTNCalculator
的文件夹。 RTN 代表 "React Native",是 React Native 模块的推荐前缀。
英Next to your application, create a folder called RTNCalculator
. RTN stands for "React Native", and is a recommended prefix for React Native modules.
在 RTNCalculator
中,创建三个子文件夹: js
、ios
和 android
。
英Within RTNCalculator
, create three subfolders: js
, ios
, and android
.
最终结果应如下所示:
英The final result should look like this:
TurboModulesGuide
├── MyApp
└── RTNCalculator
├── android
├── ios
└── js
2. JavaScript 规范
新架构 需要以 JavaScript 类型化方言(Flow 或 TypeScript)指定的接口。 代码生成器 将使用这些规范来生成强类型语言的代码,包括 C++、Objective-C++ 和 Java。
英The New Architecture requires interfaces specified in a typed dialect of JavaScript (either Flow or TypeScript). Codegen will use these specifications to generate code in strongly-typed languages, including C++, Objective-C++, and Java.
包含此规范的文件必须满足两个要求:
英There are two requirements the file containing this specification must meet:
- 文件 must 命名为
Native<MODULE_NAME>
,使用 Flow 时具有.js
或.jsx
扩展名,使用 TypeScript 时具有.ts
或.tsx
扩展名。 Codegen 将仅查找与此模式匹配的文件。 - 该文件必须导出
TurboModuleRegistrySpec
对象。
- TypeScript
- Flow
// @flow
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}
export default (TurboModuleRegistry.get<Spec>(
'RTNCalculator'
): ?Spec);
import {TurboModule, TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}
export default TurboModuleRegistry.get<Spec>(
'RTNCalculator',
) as Spec | null;
规范文件的开头是导入:
英At the beginning of the spec files are the imports:
TurboModule
类型,定义所有 Turbo Native 模块的基本接口TurboModuleRegistry
JavaScript 模块,包含加载 Turbo Native 模块的函数
文件的第二部分包含 Turbo Native 模块的接口规范。 在本例中,接口定义了 add
函数,该函数接受两个数字并返回解析为数字的 Promise。 对于 Turbo Native 模块,该接口类型 must 被命名为 Spec
。
英The second section of the file contains the interface specification for the Turbo Native Module. In this case, the interface defines the add
function, which takes two numbers and returns a promise that resolves to a number. This interface type must be named Spec
for a Turbo Native Module.
最后,我们调用 TurboModuleRegistry.get
,传递模块名称,这将加载 Turbo Native 模块(如果可用)。
英Finally, we invoke TurboModuleRegistry.get
, passing the module's name, which will load the Turbo Native Module if it's available.
我们正在编写从库导入类型的 JavaScript 文件,而无需设置适当的节点模块并安装其依赖。 你的 IDE 将无法解析导入语句,并且你可能会看到错误和警告。 这是预期的,并且当你将模块添加到应用时不会导致问题。
3. 模块配置
接下来,你需要为 代码生成器 和自动链接添加一些配置。
英Next, you need to add some configuration for Codegen and auto-linking.
一些配置文件在 iOS 和 Android 之间共享,而其他配置文件则特定于平台。
英Some configuration files are shared between iOS and Android, while the others are platform-specific.
共享
共享配置是 yarn 在安装模块时使用的 package.json
文件。 在 RTNCalculator
目录的根目录中创建 package.json
文件。
英The shared configuration is a package.json
file used by yarn when installing your module. Create the package.json
file in the root of the RTNCalculator
directory.
{
"name": "rtn-calculator",
"version": "0.0.1",
"description": "Add numbers with Turbo Native Modules",
"react-native": "js/index",
"source": "js/index",
"files": [
"js",
"android",
"ios",
"rtn-calculator.podspec",
"!android/build",
"!ios/build",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__"
],
"keywords": ["react-native", "ios", "android"],
"repository": "https://github.com/<your_github_handle>/rtn-calculator",
"author": "<Your Name> <your_email@your_provider.com> (https://github.com/<your_github_handle>)",
"license": "MIT",
"bugs": {
"url": "https://github.com/<your_github_handle>/rtn-calculator/issues"
},
"homepage": "https://github.com/<your_github_handle>/rtn-calculator#readme",
"devDependencies": {},
"peerDependencies": {
"react": "*",
"react-native": "*"
},
"codegenConfig": {
"name": "RTNCalculatorSpec",
"type": "modules",
"jsSrcsDir": "js",
"android": {
"javaPackageName": "com.rtncalculator"
}
}
}
文件的上部包含一些描述性信息,例如组件的名称、版本及其源文件。 确保更新 <>
中包含的各种占位符: 替换所有出现的 <your_github_handle>
、<Your Name>
和 <your_email@your_provider.com>
标记。
英The upper part of the file contains some descriptive information like the name of the component, its version, and its source files. Make sure to update the various placeholders which are wrapped in <>
: replace all the occurrences of the <your_github_handle>
, <Your Name>
, and <your_email@your_provider.com>
tokens.
然后是这个包的依赖。 对于本指南,你需要 react
和 react-native
。
英Then there are the dependencies for this package. For this guide, you need react
and react-native
.
最后,代码生成器 配置由 codegenConfig
字段指定。 它包含一个通过四个字段定义模块的对象:
英Finally, the Codegen configuration is specified by the codegenConfig
field. It contains an object that defines the module through four fields:
name
: 库的名称。 按照惯例,你应该添加Spec
后缀。type
: 该包包含的模块的类型。 在本例中,它是一个 Turbo Native 模块; 因此,要使用的值为modules
。jsSrcsDir
: 访问由 代码生成器 解析的js
规范的相对路径。android.javaPackageName
: 在 代码生成器 生成的 Java 文件中使用的包。
iOS:创建 podspec
文件
对于 iOS,你需要创建一个 rtn-calculator.podspec
文件,该文件会将模块定义为你的应用的依赖。 它将保留在 RTNCalculator
的根目录中,与 ios
文件夹一起。
英For iOS, you'll need to create a rtn-calculator.podspec
file, which will define the module as a dependency for your app. It will stay in the root of RTNCalculator
, alongside the ios
folder.
该文件将如下所示:
英The file will look like this:
require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
Pod::Spec.new do |s|
s.name = "rtn-calculator"
s.version = package["version"]
s.summary = package["description"]
s.description = package["description"]
s.homepage = package["homepage"]
s.license = package["license"]
s.platforms = { :ios => "11.0" }
s.author = package["author"]
s.source = { :git => package["repository"], :tag => "#{s.version}" }
s.source_files = "ios/**/*.{h,m,mm,swift}"
install_modules_dependencies(s)
end
.podspec
文件必须是 package.json
文件的同级文件,其名称是我们在 package.json
的 name
属性中设置的名称: rtn-calculator
。
英The .podspec
file has to be a sibling of the package.json
file, and its name is the one we set in the package.json
's name
property: rtn-calculator
.
文件的第一部分准备了我们在整个文件中使用的一些变量。 然后,有一个部分包含一些用于配置 Pod 的信息,例如名称、版本和描述。
英The first part of the file prepares some variables that we use throughout the file. Then, there is a section that contains some information used to configure the pod, like its name, version, and description.
新架构的所有要求都已封装在 install_modules_dependencies
中。 它负责根据当前启用的体系结构安装适当的依赖。 它还会自动在旧架构中安装 React-Core
依赖。
英All the requirements for the New Architecture have been encapsulated in the install_modules_dependencies
. It takes care of installing the proper dependencies based on which architecture is currently enabled. It also automatically installs the React-Core
dependency in the old architecture.
Android:build.gradle
和 ReactPackage
级
要准备 Android 来运行 代码生成器,你必须:
英To prepare Android to run Codegen you have to:
- 更新
build.gradle
文件。 - 实现
ReactPackage
接口的 Java/Kotlin 类
在这些步骤结束时,android
文件夹应如下所示:
英At the end of these steps, the android
folder should look like this:
android
├── build.gradle
└── src
└── main
└── java
└── com
└── rtncalculator
└── CalculatorPackage.java
build.gradle
文件
首先在 android
文件夹下创建一个 build.gradle
文件,内容如下:
英First, create a build.gradle
file in the android
folder, with the following contents:
- Java
- Kotlin
buildscript {
ext.safeExtGet = {prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
repositories {
google()
gradlePluginPortal()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.facebook.react'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 33)
namespace "com.rtncalculator"
}
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.facebook.react:react-native'
}
buildscript {
ext.safeExtGet = {prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
repositories {
google()
gradlePluginPortal()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.22")
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.facebook.react'
apply plugin: 'org.jetbrains.kotlin.android'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 33)
namespace "com.rtncalculator"
}
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.facebook.react:react-native'
}
ReactPackage
级
然后,你需要一个扩展 TurboReactPackage
接口的类。 要运行 代码生成器 进程,你不必完全实现包类: 一个空的实现足以让应用将模块作为适当的 React Native 依赖并尝试生成脚手架代码。
英Then, you need a class that extends the TurboReactPackage
interface. To run the Codegen process, you don't have to completely implement the package class: an empty implementation is enough for the app to pick up the module as a proper React Native dependency and to try and generate the scaffolding code.
创建一个 android/src/main/java/com/rtncalculator
文件夹,并在该文件夹内创建一个 CalculatorPackage.java
文件。
英Create an android/src/main/java/com/rtncalculator
folder and, inside that folder, create a CalculatorPackage.java
file.
- Java
- Kotlin
package com.rtncalculator;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.TurboReactPackage;
import java.util.Collections;
import java.util.List;
public class CalculatorPackage extends TurboReactPackage {
@Nullable
@Override
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
return null;
}
@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
return null;
}
}
package com.rtncalculator;
import com.facebook.react.TurboReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.model.ReactModuleInfoProvider
class CalculatorPackage : TurboReactPackage() {
override fun getModule(name: String?, reactContext: ReactApplicationContext): NativeModule? = null
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider? = null
}
React Native 使用 ReactPackage
接口来了解应用必须对库导出的 ViewManager
和 Native Modules
使用哪些原生类。
英React Native uses the ReactPackage
interface to understand what native classes the app has to use for the ViewManager
and Native Modules
exported by the library.
4. 原生代码
在准备好 Turbo Native 模块的最后一步中,你需要编写一些原生代码以将 JavaScript 端连接到原生平台。 这个过程需要两个主要步骤:
英For the final step in getting your Turbo Native Module ready to go, you'll need to write some native code to connect the JavaScript side to the native platforms. This process requires two main steps:
- 运行 代码生成器 查看它生成的内容。
- 编写你的原生代码,实现生成的接口。
当开发使用 Turbo Native 模块的 React Native 应用时,应用有责任使用 代码生成器 实际生成代码。 然而,当将 TurboModule 开发为库时,我们需要引用生成的代码,因此了解应用将生成的内容非常有用。
英When developing a React Native app that uses a Turbo Native Module, it is the responsibility of the app to actually generate the code using Codegen. However, when developing a TurboModule as a library, we need to reference the generated code, and it is therefore, useful to see what the app will generate.
作为 iOS 和 Android 的第一步,本指南展示了如何手动执行 代码生成器 使用的脚本来生成所需的代码。 有关 代码生成器 的更多信息可参见 here。
英As the first step for both iOS and Android, this guide shows how to execute manually the scripts used by Codegen to generate the required code. Further information on Codegen can be found here.
代码生成器 在这一步中生成的代码不应提交到版本控制系统。 React Native 应用能够在构建应用时生成代码。 这允许应用确保所有库都为正确版本的 React Native 生成了代码。
iOS
生成代码 - iOS
要运行 iOS 平台的 Codegen,我们需要打开终端并运行以下命令:
英To run Codegen for the iOS platform, we need to open a terminal and run the following command:
cd MyApp
yarn add ../RTNCalculator
cd ..
node MyApp/node_modules/react-native/scripts/generate-codegen-artifacts.js \
--path MyApp/ \
--outputPath RTNCalculator/generated/
该脚本首先使用 yarn add
将 RTNCalculator
模块添加到应用中。 然后,它通过 generate-codegen-artifacts.js
脚本调用 Codegen。
英This script first adds the RTNCalculator
module to the app with yarn add
. Then, it invokes Codegen via the generate-codegen-artifacts.js
script.
--path
选项指定应用的路径,而 --outputPath
选项告诉 Codegen 在哪里输出生成的代码。
英The --path
option specifies the path to the app, while the --outputPath
option tells Codegen where to output the generated code.
此过程的输出是以下文件夹结构:
英The output of this process is the following folder structure:
generated
└── build
└── generated
└── ios
├── FBReactNativeSpec
│ ├── FBReactNativeSpec-generated.mm
│ └── FBReactNativeSpec.h
├── RCTThirdPartyFabricComponentsProvider.h
├── RCTThirdPartyFabricComponentsProvider.mm
├── RTNCalculatorSpec
│ ├── RTNCalculatorSpec-generated.mm
│ └── RTNCalculatorSpec.h
└── react
└── renderer
└── components
└── rncore
├── ComponentDescriptors.h
├── EventEmitters.cpp
├── EventEmitters.h
├── Props.cpp
├── Props.h
├── RCTComponentViewHelpers.h
├── ShadowNodes.cpp
└── ShadowNodes.h
Turbo Native Module 接口的相关路径是 generated/build/generated/ios/RTNCalculatorSpec
。
英The relevant path for the Turbo Native Module interface is generated/build/generated/ios/RTNCalculatorSpec
.
有关生成文件的更多详细信息,请参阅 代码生成器 部分。
英See the Codegen section for further details on the generated files.
使用 代码生成器 生成脚手架代码时,iOS 不会自动清理 build
文件夹。 例如,如果你更改了 Spec 名称,然后再次运行 代码生成器,则旧文件将被保留。
如果发生这种情况,请记住在再次运行 代码生成器 之前删除 build
文件夹。
英When generating the scaffolding code using Codegen, iOS does not clean the build
folder automatically. If you changed the Spec name, for example, and then run Codegen again, the old files would be retained.
If that happens, remember to remove the build
folder before running the Codegen again.
cd MyApp/ios
rm -rf build
编写原生 iOS 代码
现在为你的 Turbo Native 模块添加原生代码。 在 RTNCalculator/ios
文件夹中创建两个文件:
英Now add the Native code for your Turbo Native Module. Create two files in the RTNCalculator/ios
folder:
RTNCalculator.h
,模块的头文件。RTNCalculator.mm
,模块的实现。
RTNCalculator.h
#import <RTNCalculatorSpec/RTNCalculatorSpec.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTNCalculator : NSObject <NativeCalculatorSpec>
@end
NS_ASSUME_NONNULL_END
该文件定义了 RTNCalculator
模块的接口。 在这里,我们可以添加我们可能想要在视图上调用的任何原生方法。 对于本指南,我们不需要任何东西,因此界面是空的。
英This file defines the interface for the RTNCalculator
module. Here, we can add any native method we may want to invoke on the view. For this guide, we don't need anything, therefore the interface is empty.
RTNCalculator.mm
#import "RTNCalculatorSpec.h"
#import "RTNCalculator.h"
@implementation RTNCalculator
RCT_EXPORT_MODULE()
- (void)add:(double)a b:(double)b resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
NSNumber *result = [[NSNumber alloc] initWithInteger:a+b];
resolve(result);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeCalculatorSpecJSI>(params);
}
@end
最重要的调用是 RCT_EXPORT_MODULE
,它需要导出模块,以便 React Native 可以加载 Turbo Native 模块。
英The most important call is to the RCT_EXPORT_MODULE
, which is required to export the module so that React Native can load the Turbo Native Module.
然后是 add
方法,其签名必须与 RTNCalculatorSpec.h
中 Codegen 指定的签名相匹配。
英Then the add
method, whose signature must match the one specified by the Codegen in the RTNCalculatorSpec.h
.
最后,getTurboModule
方法获取 Turbo Native Module 的实例,以便 JavaScript 端可以调用其方法。 该函数在 Codegen 之前生成的 RTNCalculatorSpec.h
文件中定义(并由其请求)。
英Finally, the getTurboModule
method gets an instance of the Turbo Native Module so that the JavaScript side can invoke its methods. The function is defined in (and requested by) the RTNCalculatorSpec.h
file that was generated earlier by Codegen.
还有其他宏可用于导出模块和方法。 你查看指定它们 here 的代码。
安卓
Android 遵循与 iOS 类似的步骤。 我们必须生成 Android 代码,然后我们必须编写一些原生代码才能使其工作。
英Android follows similar steps to iOS. We have to generate the code for Android, and then we have to write some native code to make it work.
生成代码 - Android
要生成 Android 代码,我们需要手动调用 Codegen。 这与我们对 iOS 所做的类似: 首先,我们需要将包添加到应用中,然后我们需要调用脚本。
英To generate the code for Android, we need to manually invoke Codegen. This is done similarly to what we did for iOS: first, we need to add the package to the app, and then we need to invoke a script.
cd MyApp
yarn add ../RTNCalculator
cd android
./gradlew generateCodegenArtifactsFromSchema
该脚本首先将包添加到应用中,与 iOS 的方式相同。 然后,在移动到 android
文件夹后,它调用 Gradle 任务来创建生成的代码。
英This script first adds the package to the app, in the same way iOS does. Then, after moving to the android
folder, it invokes a Gradle task to create the generated code.
要运行 代码生成器,你需要在 Android 应用中启用 新架构。 这可以通过打开 gradle.properties
文件并将 newArchEnabled
属性从 false
切换到 true
来完成。
生成的代码存储在 MyApp/node_modules/rtn-calculator/android/build/generated/source/codegen
文件夹中,其结构如下:
英The generated code is stored in the MyApp/node_modules/rtn-calculator/android/build/generated/source/codegen
folder and it has this structure:
codegen
├── java
│ └── com
│ └── rtncalculator
│ └── NativeCalculatorSpec.java
├── jni
│ ├── Android.mk
│ ├── CMakeLists.txt
│ ├── RTNCalculator-generated.cpp
│ ├── RTNCalculator.h
│ └── react
│ └── renderer
│ └── components
│ └── RTNCalculator
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── ShadowNodes.cpp
│ └── ShadowNodes.h
└── schema.json
编写原生 Android 代码
Turbo Native 模块 Android 端的原生代码需要:
英The native code for the Android side of a Turbo Native Module requires:
- 创建一个实现该模块的
CalculatorModule.java
。 - 更新在上一步中创建的
CalculatorPackage.java
。
Android 库中的最终结构应如下所示:
英The final structure within the Android library should look like this:
android
├── build.gradle
└── src
└── main
└── java
└── com
└── rtncalculator
├── CalculatorModule.java
└── CalculatorPackage.java
创建 CalculatorModule.java
- Java
- Kotlin
package com.rtncalculator;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import com.rtncalculator.NativeCalculatorSpec;
public class CalculatorModule extends NativeCalculatorSpec {
public static String NAME = "RTNCalculator";
CalculatorModule(ReactApplicationContext context) {
super(context);
}
@Override
@NonNull
public String getName() {
return NAME;
}
@Override
public void add(double a, double b, Promise promise) {
promise.resolve(a + b);
}
}
package com.rtncalculator
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.rtncalculator.NativeCalculatorSpec
class CalculatorModule(reactContext: ReactApplicationContext) : NativeCalculatorSpec(reactContext) {
override fun getName() = NAME
override fun add(a: Double, b: Double, promise: Promise) {
promise.resolve(a + b)
}
companion object {
const val NAME = "RTNCalculator"
}
}
此类实现模块本身,它扩展了从 NativeCalculator
JavaScript 规范文件生成的 NativeCalculatorSpec
。
英This class implements the module itself, which extends the NativeCalculatorSpec
that was generated from the NativeCalculator
JavaScript specification file.
更新 CalculatorPackage.java
- Java
- Kotlin
package com.rtncalculator;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
+ import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.TurboReactPackage;
import java.util.Collections;
import java.util.List;
+ import java.util.HashMap;
+ import java.util.Map;
public class CalculatorPackage extends TurboReactPackage {
@Nullable
@Override
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
+ if (name.equals(CalculatorModule.NAME)) {
+ return new CalculatorModule(reactContext);
+ } else {
return null;
+ }
}
@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
- return null;
+ return () -> {
+ final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
+ moduleInfos.put(
+ CalculatorModule.NAME,
+ new ReactModuleInfo(
+ CalculatorModule.NAME,
+ CalculatorModule.NAME,
+ false, // canOverrideExistingModule
+ false, // needsEagerInit
+ true, // hasConstants
+ false, // isCxxModule
+ true // isTurboModule
+ ));
+ return moduleInfos;
+ };
}
}
package com.rtncalculator;
import com.facebook.react.TurboReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.module.model.ReactModuleInfo
import com.facebook.react.module.model.ReactModuleInfoProvider
class CalculatorPackage : TurboReactPackage() {
- override fun getModule(name: String?, reactContext: ReactApplicationContext): NativeModule? = null
+ override fun getModule(name: String?, reactContext: ReactApplicationContext): NativeModule? =
+ if (name == CalculatorModule.NAME) {
+ CalculatorModule(reactContext)
+ } else {
+ null
+ }
- override fun getReactModuleInfoProvider() = ReactModuleInfoProvider? = null
+ override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
+ mapOf(
+ CalculatorModule.NAME to ReactModuleInfo(
+ CalculatorModule.NAME,
+ CalculatorModule.NAME,
+ false, // canOverrideExistingModule
+ false, // needsEagerInit
+ true, // hasConstants
+ false, // isCxxModule
+ true // isTurboModule
+ )
+ )
+ }
}
这是 Android 的最后一段原生代码。 它定义了应用将使用的 TurboReactPackage
对象来加载模块。
英This is the last piece of Native Code for Android. It defines the TurboReactPackage
object that will be used by the app to load the module.
最终结构
最终的结构应该是这样的:
英The final structure should look like this:
TurboModulesGuide
├── MyApp
└── RTNCalculator
├── android
│ ├── build.gradle
│ └── src
│ └── main
│ └── java
│ └── com
│ └── rtncalculator
│ ├── CalculatorPackage.java
│ └── CalculatorModule.java
├── generated
├── ios
│ ├── RTNCalculator.h
│ └── RTNCalculator.mm
├── js
│ └── NativeCalculator.ts
├── package.json
└── rtn-calculator.podspec
5. 将 Turbo Native 模块添加到你的应用中
现在你可以在应用中安装和使用 Turbo Native 模块。
英Now you can install and use the Turbo Native Module in your app.
共享
首先,我们需要将包含组件的 NPM 包添加到应用中。 这可以通过以下命令来完成:
英First of all, we need to add the NPM package which contains the Component to the app. This can be done with the following command:
cd MyApp
yarn add ../RTNCalculator
此命令会将 RTNCalculator
模块添加到应用的 node_modules
中。
英This command will add the RTNCalculator
module to the node_modules
of your app.
iOS
然后,你需要在 iOS 项目中安装新的依赖。 为此,请运行以下命令:
英Then, you need to install the new dependencies in your iOS project. To do so, run these commands:
cd ios
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
此命令将查找项目的所有依赖并安装 iOS 依赖。 RCT_NEW_ARCH_ENABLED=1
指示 CocoaPods 必须运行一些附加操作才能运行 代码生成器。
英This command will look for all the dependencies of the project and it will install the iOS ones. The RCT_NEW_ARCH_ENABLED=1
instruct CocoaPods that it has to run some additional operations to run Codegen.
你可能必须运行 bundle install
一次才能使用 RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
。 你将不再需要运行 bundle install
,除非你需要更改 Ruby 依赖。
安卓
Android 配置需要启用 新架构:
英Android configuration requires to enable the New Architecture:
- 打开
android/gradle.properties
文件 - 向下滚动到文件末尾并将
newArchEnabled
属性从false
切换到true
。
JavaScript
现在你可以在应用中使用 Turbo Native Module 计算器!
英Now you can use your Turbo Native Module calculator in your app!
以下是使用 add
方法的 App.js 文件示例:
英Here's an example App.js file using the add
method:
- TypeScript
- Flow
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {useState} from 'react';
import type {Node} from 'react';
import {
SafeAreaView,
StatusBar,
Text,
Button,
} from 'react-native';
import RTNCalculator from 'rtn-calculator/js/NativeCalculator';
const App: () => Node = () => {
const [result, setResult] = useState<number | null>(null);
return (
<SafeAreaView>
<StatusBar barStyle={'dark-content'} />
<Text style={{marginLeft: 20, marginTop: 20}}>
3+7={result ?? '??'}
</Text>
<Button
title="Compute"
onPress={async () => {
const value = await RTNCalculator.add(3, 7);
setResult(value);
}}
/>
</SafeAreaView>
);
};
export default App;
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React from 'react';
import {useState} from 'react';
import {
SafeAreaView,
StatusBar,
Text,
Button,
} from 'react-native';
import RTNCalculator from 'rtn-calculator/js/NativeCalculator';
const App: () => JSX.Element = () => {
const [result, setResult] = useState<number | null>(null);
return (
<SafeAreaView>
<StatusBar barStyle={'dark-content'} />
<Text style={{marginLeft: 20, marginTop: 20}}>
3+7={result ?? '??'}
</Text>
<Button
title="Compute"
onPress={async () => {
const value = await RTNCalculator?.add(3, 7);
setResult(value ?? null);
}}
/>
</SafeAreaView>
);
};
export default App;
尝试一下,看看你的 Turbo Native 模块正在运行!
英Try this out to see your Turbo Native Module in action!