Skip to main content

原生模块

¥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:

  1. 使用最流行的 JavaScript 类型注释语言之一定义类型化的 JavaScript 规范:Flow 或 TypeScript;

    ¥define a typed JavaScript specification using one of the most popular JavaScript type annotation languages: Flow or TypeScript;

  2. 配置你的依赖管理系统以运行 Codegen,它将规范转换为原生语言接口;

    ¥configure your dependency management system to run Codegen, which converts the specification into native language interfaces;

  3. 使用你的规范编写你的应用代码;and

    ¥write your application code using your specification; and

  4. 使用生成的接口编写你的原生平台代码,以编写并将你的原生代码挂接到 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:

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:

  1. 在应用的根文件夹中,创建一个名为 specs 的新文件夹。

    ¥Inside the root folder of your app, create a new folder called specs.

  2. 创建一个名为 NativeLocalStorage.ts 的新文件。

    ¥Create a new file called NativeLocalStorage.ts.

信息

你可以看到你可以在规范中使用的所有类型以及在 附录 文档中生成的原生类型。

¥You can see all of the types you can use in your specification and the native types that are generated in the Appendix documentation.

这是 localStorage 规范的实现:

¥Here is an implementation of the localStorage specification:

specs/NativeLocalStorage.ts
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',
);

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:

package.json
     "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.

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.

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 return null 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.

App.tsx
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.

    <TurboNativeModulesAndroid />