Przejdź do treści głównej
Wersja: 0.80
Nieoficjalne Tłumaczenie Beta

Ta strona została przetłumaczona przez PageTurner AI (beta). Nie jest oficjalnie zatwierdzona przez projekt. Znalazłeś błąd? Zgłoś problem →

Moduły natywne

Twój kod aplikacji React Native może potrzebować interakcji z natywnymi API platformy, które nie są dostarczane przez React Native ani istniejącą bibliotekę. Możesz samodzielnie napisać kod integracyjny, używając modułu Turbo Native. Ten przewodnik pokaże ci, jak go stworzyć.

Podstawowe kroki to:

  1. zdefiniuj typowaną specyfikację JavaScript przy użyciu jednego z popularnych języków adnotacji typów: Flow lub TypeScript;

  2. skonfiguruj system zarządzania zależnościami do uruchomienia Codegen, który konwertuje specyfikację na interfejsy w językach natywnych;

  3. napisz kod aplikacji korzystając ze swojej specyfikacji; oraz

  4. napisz natywny kod platformy wykorzystując wygenerowane interfejsy, aby zaimplementować i podłączyć swój kod natywny do środowiska wykonawczego React Native.

Przejdźmy przez każdy z tych kroków, budując przykładowy moduł Turbo Native. Reszta przewodnika zakłada, że utworzyłeś aplikację uruchamiając polecenie:

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

Trwałe przechowywanie danych

Ten przewodnik pokaże ci, jak zaimplementować Web Storage API: localStorage. To API jest znane programistom Reacta, którzy mogą pisać kod aplikacji w twoim projekcie.

Aby to działało na urządzeniach mobilnych, musimy użyć API Androida i iOS:

1. Deklaracja typowanej specyfikacji

React Native udostępnia narzędzie o nazwie Codegen, które przyjmuje specyfikację napisaną w TypeScript lub Flow i generuje platformowo specyficzny kod dla Androida i iOS. Specyfikacja deklaruje metody i typy danych, które będą przekazywane między twoim kodem natywnym a środowiskiem wykonawczym JavaScript React Native. Moduł Turbo Native to zarówno twoja specyfikacja, natywny kod, który piszesz, jak i interfejsy Codegen wygenerowane z twojej specyfikacji.

Aby utworzyć plik specyfikacji:

  1. W głównym folderze aplikacji utwórz nowy folder o nazwie specs.

  2. Utwórz nowy plik o nazwie NativeLocalStorage.ts.

informacja

Wszystkie typy, które możesz użyć w swojej specyfikacji oraz typy natywne, które są generowane, znajdziesz w dokumentacji Dodatku.

informacja

Jeśli chcesz zmienić nazwę modułu i powiązanego pliku specyfikacji, upewnij się, że zawsze używasz prefiksu 'Native' (np. NativeStorage lub NativeUsersDefault).

Oto implementacja specyfikacji 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. Konfiguracja uruchomienia Codegen

Specyfikacja jest używana przez narzędzia Codegen React Native do generowania interfejsów specyficznych dla platform i szablonów kodu. Aby to zrobić, Codegen musi wiedzieć, gdzie znaleźć naszą specyfikację i co z nią zrobić. Zaktualizuj swój package.json, dodając:

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

Po skonfigurowaniu Codegen, musimy przygotować nasz kod natywny do integracji z wygenerowanym kodem.

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. Pisanie kodu aplikacji z użyciem modułu Turbo Native

Korzystając z NativeLocalStorage, oto zmodyfikowany App.tsx, który zawiera tekst do utrwalenia, pole wprowadzania i przyciski do aktualizacji tej wartości.

TurboModuleRegistry obsługuje 2 tryby pobierania modułu Turbo Native:

  • get<T>(name: string): T | null zwróci null, jeśli moduł Turbo Native jest niedostępny.

  • getEnforcing<T>(name: string): T zgłosi wyjątek, jeśli moduł Turbo Native jest niedostępny. Zakłada, że moduł jest zawsze dostępny.

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. Pisanie natywnego kodu platformy

Po przygotowaniu wszystkiego zaczniemy pisać natywny kod platformy. Robimy to w 2 częściach:

uwaga

Ten poradnik pokazuje, jak utworzyć moduł Turbo Native Module, który działa wyłącznie z Nową Architekturą. Jeśli potrzebujesz obsługiwać zarówno Nową Architekturę, jak i Starszą Architekturę, zapoznaj się z naszym przewodnikiem dotyczącym zgodności wstecznej.

Nieoficjalne Tłumaczenie Beta

Ta strona została przetłumaczona przez PageTurner AI (beta). Nie jest oficjalnie zatwierdzona przez projekt. Znalazłeś błąd? Zgłoś problem →

Teraz czas napisać kod na platformie Android, aby zapewnić, że localStorage przetrwa po zamknięciu aplikacji.

Pierwszym krokiem jest zaimplementowanie wygenerowanego interfejsu 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();
}
}

Następnie musimy utworzyć NativeLocalStoragePackage. Dostarcza on obiekt rejestrujący nasz moduł w środowisku wykonawczym React Native poprzez opakowanie go jako Base Native Package:

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;
}
};
}
}

Na koniec musimy wskazać React Native w naszej głównej aplikacji, jak znaleźć ten Package. Proces ten nazywamy "rejestracją" pakietu w React Native.

W tym przypadku dodajesz go do wartości zwracanej przez metodę getPackages.

informacja

Później dowiesz się, jak dystrybuować swoje moduły natywne jako pakiety npm, które nasze narzędzia do budowania automatycznie podlinkują.

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();
}
}
}

Możesz teraz zbudować i uruchomić swój kod na emulatorze:

bash
npm run android