Saltar al contenido principal
Versión: 0.82
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Módulos nativos

Es posible que tu código de aplicación React Native necesite interactuar con APIs nativas de plataforma que no están proporcionadas por React Native ni por bibliotecas existentes. Puedes escribir tú mismo el código de integración usando un Módulo Nativo Turbo. Esta guía te mostrará cómo escribir uno.

Los pasos básicos son:

  1. definir una especificación JavaScript tipada usando uno de los lenguajes de anotación de tipos más populares: Flow o TypeScript;

  2. configurar tu sistema de gestión de dependencias para ejecutar Codegen, que convierte la especificación en interfaces de lenguaje nativo;

  3. escribir tu código de aplicación usando tu especificación; y

  4. escribir tu código de plataforma nativa usando las interfaces generadas para implementar y conectar tu código nativo al entorno de ejecución de React Native.

Trabajemos cada uno de estos pasos construyendo un ejemplo de Módulo Nativo Turbo. El resto de esta guía asume que has creado tu aplicación ejecutando el comando:

shell
npx @react-native-community/cli@latest init TurboModuleExample --version 0.82

Almacenamiento persistente nativo

Esta guía te mostrará cómo escribir una implementación de la API Web Storage: localStorage. La API es familiar para desarrolladores React que podrían estar escribiendo código de aplicación en tu proyecto.

Para que esto funcione en móviles, necesitamos usar APIs de Android e iOS:

1. Declarar la especificación tipada

React Native proporciona una herramienta llamada Codegen que toma una especificación escrita en TypeScript o Flow y genera código específico para las plataformas Android e iOS. La especificación declara los métodos y tipos de datos que se intercambiarán entre tu código nativo y el entorno de ejecución JavaScript de React Native. Un Turbo Native Module incluye tanto tu especificación, el código nativo que escribes, como las interfaces de Codegen generadas a partir de tu especificación.

Para crear un archivo de especificaciones:

  1. Dentro de la carpeta raíz de tu aplicación, crea una nueva carpeta llamada specs.

  2. Crea un nuevo archivo llamado NativeLocalStorage.ts.

:::información Puedes ver todos los tipos que puedes usar en tu especificación y los tipos nativos que se generan en la documentación del Apéndice. :::

:::información Si deseas cambiar el nombre de tu módulo y el archivo de especificaciones relacionado, asegúrate de siempre usar el prefijo 'Native' (por ejemplo, NativeStorage o NativeUsersDefault). :::

Aquí hay una implementación de la especificación localStorage:

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. Configurar la ejecución de Codegen

La especificación es utilizada por las herramientas Codegen de React Native para generar interfaces específicas de plataforma y código repetitivo. Para hacer esto, Codegen necesita saber dónde encontrar nuestra especificación y qué hacer con ella. Actualiza tu package.json para incluir:

package.json
     "start": "react-native start",
"test": "jest"
},
"codegenConfig": {
"name": "NativeLocalStorageSpec",
"type": "modules",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.nativelocalstorage"
}
},
"dependencies": {

Con todo configurado para Codegen, necesitamos preparar nuestro código nativo para conectarse con el código generado.

Codegen is executed through the generateCodegenArtifactsFromSchema Gradle task:

bash
cd android
./gradlew generateCodegenArtifactsFromSchema

BUILD SUCCESSFUL in 837ms
14 actionable tasks: 3 executed, 11 up-to-date

This is automatically run when you build your Android application.

3. Escribir código de aplicación usando el Módulo Nativo Turbo

Usando NativeLocalStorage, aquí hay un App.tsx modificado que incluye un texto que queremos persistir, un campo de entrada y algunos botones para actualizar este valor.

El TurboModuleRegistry admite 2 modos para recuperar un Módulo Nativo Turbo:

  • get<T>(name: string): T | null que devolverá null si el Módulo Nativo Turbo no está disponible.

  • getEnforcing<T>(name: string): T que lanzará una excepción si el Módulo Nativo Turbo no está disponible. Esto asume que el módulo siempre está disponible.

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('myKey');
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. Escribir tu código de plataforma nativa

Con todo preparado, vamos a comenzar a escribir código de plataforma nativa. Hacemos esto en 2 partes:

Esta guía te muestra cómo crear un Turbo Native Module que solo funciona con la Nueva Arquitectura. Si necesitas admitir tanto la Nueva Arquitectura como la Arquitectura Legacy, consulta nuestra guía de compatibilidad con versiones anteriores.

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Ahora es momento de escribir código de plataforma Android para asegurar que localStorage persista después de cerrar la aplicación.

El primer paso es implementar la interfaz generada NativeLocalStorageSpec:

android/app/src/main/java/com/nativelocalstorage/NativeLocalStorageModule.java
package com.nativelocalstorage;

import android.content.Context;
import android.content.SharedPreferences;
import com.nativelocalstorage.NativeLocalStorageSpec;
import com.facebook.react.bridge.ReactApplicationContext;

public class NativeLocalStorageModule extends NativeLocalStorageSpec {

public static final String NAME = "NativeLocalStorage";

public NativeLocalStorageModule(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public String getName() {
return NAME;
}

@Override
public void setItem(String value, String key) {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(key, value);
editor.apply();
}

@Override
public String getItem(String key) {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
String username = sharedPref.getString(key, null);
return username;
}

@Override
public void removeItem(String key) {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
sharedPref.edit().remove(key).apply();
}

@Override
public void clear() {
SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
sharedPref.edit().clear().apply();
}
}

Luego necesitamos crear NativeLocalStoragePackage. Este provee un objeto para registrar nuestro Módulo en el entorno de ejecución de React Native, envolviéndolo como un Paquete Nativo Base:

android/app/src/main/java/com/nativelocalstorage/NativeLocalStoragePackage.java
package com.nativelocalstorage;

import com.facebook.react.BaseReactPackage;
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 java.util.HashMap;
import java.util.Map;

public class NativeLocalStoragePackage extends BaseReactPackage {

@Override
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
if (name.equals(NativeLocalStorageModule.NAME)) {
return new NativeLocalStorageModule(reactContext);
} else {
return null;
}
}

@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
return new ReactModuleInfoProvider() {
@Override
public Map<String, ReactModuleInfo> getReactModuleInfos() {
Map<String, ReactModuleInfo> map = new HashMap<>();
map.put(NativeLocalStorageModule.NAME, new ReactModuleInfo(
NativeLocalStorageModule.NAME, // name
NativeLocalStorageModule.NAME, // className
false, // canOverrideExistingModule
false, // needsEagerInit
false, // isCXXModule
true // isTurboModule
));
return map;
}
};
}
}

Finalmente, debemos indicarle a React Native en nuestra aplicación principal cómo encontrar este Package. A esto lo llamamos "registrar" el paquete en React Native.

En este caso, lo agregas para que sea devuelto por el método getPackages.

información

Más adelante aprenderás a distribuir tus Módulos Nativos como paquetes npm, que nuestras herramientas de compilación enlazarán automáticamente.

android/app/src/main/java/com/turobmoduleexample/MainApplication.java
package com.inappmodule;

import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactHost;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactHost;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import com.nativelocalstorage.NativeLocalStoragePackage;

import java.util.ArrayList;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost reactNativeHost = new DefaultReactNativeHost(this) {
@Override
public List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new NativeLocalStoragePackage());
return packages;
}

@Override
public String getJSMainModuleName() {
return "index";
}

@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

@Override
public boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}

@Override
public boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};

@Override
public ReactHost getReactHost() {
return DefaultReactHost.getDefaultReactHost(getApplicationContext(), reactNativeHost);
}

@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
}
}
}

Ahora puedes compilar y ejecutar tu código en un emulador:

bash
npm run android