原生模块
¥Native Modules
你的 React Native 应用代码可能需要与 React Native 或现有库未提供的原生平台 API 进行交互。你可以使用 Turbo Native 模块自己编写集成代码。本指南将向你展示如何编写一个。
¥Your React Native application code may need to interact with native platform APIs that aren't provided by React Native or an existing library. You can write the integration code yourself using a Turbo Native Module. This guide will show you how to write one.
基本步骤是:
¥The basic steps are:
-
使用最流行的 JavaScript 类型注释语言之一定义类型化的 JavaScript 规范:Flow 或 TypeScript;
¥define a typed JavaScript specification using one of the most popular JavaScript type annotation languages: Flow or TypeScript;
-
配置你的依赖管理系统以运行 Codegen,它将规范转换为原生语言接口;
¥configure your dependency management system to run Codegen, which converts the specification into native language interfaces;
-
使用你的规范编写你的应用代码;and
¥write your application code using your specification; and
-
使用生成的接口编写你的原生平台代码,以编写并将你的原生代码挂接到 React Native 运行时环境中。
¥write your native platform code using the generated interfaces to write and hook your native code into the React Native runtime environment.
让我们通过构建一个示例 Turbo Native 模块来完成每个步骤。本指南的其余部分假设你已创建运行以下命令的应用:
¥Lets work through each of these steps by building an example Turbo Native Module. The rest of this guide assume that you have created your application running the command:
npx @react-native-community/cli@latest init TurboModuleExample --version 0.76.0
原生持久存储
¥Native Persistent Storage
本指南将向你展示如何编写 Web 存储 API 的实现:localStorage
。该 API 与可能在你的项目上编写应用代码的 React 开发者相关。
¥This guide will show you how to write an implementation of the Web Storage API: localStorage
. The API is relatable to a React developer who might be writing application code on your project.
为了使其在移动设备上工作,我们需要使用 Android 和 iOS API:
¥To make this work on mobile, we need to use Android and iOS APIs:
-
安卓:SharedPreferences,和
¥Android: SharedPreferences, and
-
iOS:NSUserDefaults。
1. 声明类型规范
¥ Declare Typed Specification
React Native 提供了一个名为 Codegen 的工具,它采用用 TypeScript 或 Flow 编写的规范并为 Android 和 iOS 生成特定于平台的代码。规范声明了将在你的原生代码和 React Native JavaScript 运行时之间来回传递的方法和数据类型。Turbo Native 模块既是你的规范,也是你编写的原生代码,也是从你的规范生成的 Codegen 接口。
¥React Native provides a tool called Codegen, which takes a specification written in TypeScript or Flow and generates platform specific code for Android and iOS. The specification declares the methods and data types that will pass back and forth between your native code and the React Native JavaScript runtime. A Turbo Native Module is both your specification, the native code you write, and the Codegen interfaces generated from your specification.
要创建一个 specs 文件:
¥To create a specs file:
-
在应用的根文件夹中,创建一个名为
specs
的新文件夹。¥Inside the root folder of your app, create a new folder called
specs
. -
创建一个名为
NativeLocalStorage.ts
的新文件。¥Create a new file called
NativeLocalStorage.ts
.
这是 localStorage
规范的实现:
¥Here is an implementation of the localStorage
specification:
- TypeScript
- Flow
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
setItem(value: string, key: string): void;
getItem(key: string): string | null;
removeItem(key: string): void;
clear(): void;
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeLocalStorage',
);
import type {TurboModule} from 'react-native';
import {TurboModule, TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
setItem(value: string, key: string): void;
getItem(key: string): ?string;
removeItem(key: string): void;
clear(): void;
}
2. 配置 Codegen 以运行
¥ Configure Codegen to run
React Native Codegen 工具使用该规范为我们生成特定于平台的接口和样板。为此,Codegen 需要知道在哪里找到我们的规范以及如何处理它。更新你的 package.json
以包含:
¥The specification is used by the React Native Codegen tools to generate platform specific interfaces and boilerplate for us. To do this, Codegen needs to know where to find our specification and what to do with it. Update your package.json
to include:
"start": "react-native start",
"test": "jest"
},
"codegenConfig": {
"name": "NativeLocalStorageSpec",
"type": "modules",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.nativelocalstorage"
}
},
"dependencies": {
为 Codegen 连接好所有内容后,我们需要准备原生代码以挂接到我们生成的代码中。
¥With everything wired up for Codegen, we need to prepare our native code to hook into our generated code.
- Android
- iOS
Codegen 通过 generateCodegenArtifactsFromSchema
Gradle 任务执行:
¥Codegen is executed through the generateCodegenArtifactsFromSchema
Gradle task:
cd android
./gradlew generateCodegenArtifactsFromSchema
BUILD SUCCESSFUL in 837ms
14 actionable tasks: 3 executed, 11 up-to-date
这将在你构建 Android 应用时自动运行。
¥This is automatically run when you build your Android application.
Codegen 作为脚本阶段的一部分运行,会自动添加到 CocoaPods 生成的项目中。
¥Codegen is run as part of the script phases that's automatically added to the project generated by CocoaPods.
cd ios
bundle install
bundle exec pod install
输出将如下所示:
¥The output will look like this:
...
Framework build type is static library
[Codegen] Adding script_phases to ReactCodegen.
[Codegen] Generating ./build/generated/ios/ReactCodegen.podspec.json
[Codegen] Analyzing /Users/me/src/TurboModuleExample/package.json
[Codegen] Searching for codegen-enabled libraries in the app.
[Codegen] Found TurboModuleExample
[Codegen] Searching for codegen-enabled libraries in the project dependencies.
[Codegen] Found react-native
...
3. 使用 Turbo Native 模块编写应用代码
¥ Write Application Code using the Turbo Native Module
使用 NativeLocalStorage
,这是一个修改后的 App.tsx
,其中包含一些我们想要保留的文本、一个输入字段和一些用于更新此值的按钮。
¥Using NativeLocalStorage
, here’s a modified App.tsx
that includes some text we want persisted, an input field and some buttons to update this value.
TurboModuleRegistry
支持 2 种检索 Turbo Native 模块的模式:
¥The TurboModuleRegistry
supports 2 modes of retrieving a Turbo Native Module:
-
如果 Turbo Native 模块不可用,则
get<T>(name: string): T | null
将返回null
。¥
get<T>(name: string): T | null
which will returnnull
if the Turbo Native Module is unavailable. -
getEnforcing<T>(name: string): T
如果 Turbo Native 模块不可用,它将抛出异常。这假设模块始终可用。¥
getEnforcing<T>(name: string): T
which will throw an exception if the Turbo Native Module is unavailable. This assumes the module is always available.
import React from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
TextInput,
Button,
} from 'react-native';
import NativeLocalStorage from './specs/NativeLocalStorage';
const EMPTY = '<empty>';
function App(): React.JSX.Element {
const [value, setValue] = React.useState<string | null>(null);
const [editingValue, setEditingValue] = React.useState<
string | null
>(null);
React.useEffect(() => {
const storedValue = NativeLocalStorage?.getItem('myKey');
setValue(storedValue ?? '');
}, []);
function saveValue() {
NativeLocalStorage?.setItem(editingValue ?? EMPTY, 'myKey');
setValue(editingValue);
}
function clearAll() {
NativeLocalStorage?.clear();
setValue('');
}
function deleteValue() {
NativeLocalStorage?.removeItem(editingValue ?? EMPTY);
setValue('');
}
return (
<SafeAreaView style={{flex: 1}}>
<Text style={styles.text}>
Current stored value is: {value ?? 'No Value'}
</Text>
<TextInput
placeholder="Enter the text you want to store"
style={styles.textInput}
onChangeText={setEditingValue}
/>
<Button title="Save" onPress={saveValue} />
<Button title="Delete" onPress={deleteValue} />
<Button title="Clear" onPress={clearAll} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
text: {
margin: 10,
fontSize: 20,
},
textInput: {
margin: 10,
height: 40,
borderColor: 'black',
borderWidth: 1,
paddingLeft: 5,
paddingRight: 5,
borderRadius: 5,
},
});
export default App;
4. 编写你的原生平台代码
¥ Write your Native Platform code
一切准备就绪后,我们将开始编写原生平台代码。我们分两部分进行:
¥With everything prepared, we're going to start writing native platform code. We do this in 2 parts:
本指南向你展示如何创建仅适用于新架构的 Turbo Native 模块。如果你需要同时支持新架构和旧架构,请参考我们的 向后兼容性指南。
¥This guide shows you how to create a Turbo Native Module that only works with the New Architecture. If you need to support both the New Architecture and the Legacy Architecture, please refer to our backwards compatibility guide.
- Android
- iOS
<TurboNativeModulesAndroid />
<TurboNativeModulesIOS/>