Przejdź do treści głównej
Wersja: 0.78
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 →

Wieloplatformowe moduły natywne (C++)

Pisanie modułu w C++ to najlepszy sposób na współdzielenie kodu niezależnego od platformy między Androidem a iOS. Dzięki czystym modułom C++ możesz napisać logikę tylko raz i natychmiast wykorzystać ją na wszystkich platformach, bez konieczności tworzenia kodu specyficznego dla danej platformy.

W tym przewodniku krok po kroku stworzymy czysty moduł Turbo Native w C++:

  1. Utwórz specyfikacje JS

  2. Skonfiguruj Codegen do generowania szkieletu

  3. Zaimplementuj logikę natywną

  4. Zarejestruj moduł w aplikacjach na Androida i iOS

  5. Przetestuj zmiany w JS

Poniższa część przewodnika zakłada, że aplikacja została utworzona za pomocą polecenia:

shell
npx @react-native-community/cli@latest init SampleApp --version 0.78

1. Utwórz specyfikacje JS​

Czyste moduły Turbo Native w C++ wymagają pliku specyfikacji (zwanego spec file), aby Codegen mógł wygenerować dla nas szkielet kodu. Ten plik specyfikacji służy również do dostępu do modułu Turbo Native z poziomu JS.

Pliki specyfikacji muszą być napisane w typowanym dialekcie JS. React Native obsługuje obecnie Flow lub TypeScript.

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

  2. Utwórz nowy plik NativeSampleModule.ts z następującym kodem:

ostrzeżenie

Wszystkie pliki specyfikacji modułów Turbo Native muszą mieć prefiks Native - w przeciwnym razie Codegen je zignoruje.

specs/NativeSampleModule.ts
import {TurboModule, TurboModuleRegistry} from 'react-native';

export interface Spec extends TurboModule {
readonly reverseString: (input: string) => string;
}

export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeSampleModule',
);

2. Skonfiguruj Codegen​

Następnym krokiem jest skonfigurowanie Codegen w pliku package.json. Zaktualizuj plik, dodając:

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

Ta konfiguracja mówi Codegen, aby szukał plików specyfikacji w folderze specs. Instruuje również Codegen, aby generował kod tylko dla modules i nadał wygenerowanemu kodowi przestrzeń nazw AppSpecs.

3. Napisz kod natywny​

Tworzenie modułu Turbo Native w C++ umożliwia współdzielenie kodu między Androidem a iOS. Oznacza to, że kod piszemy tylko raz, a następnie dostosowujemy platformy, aby mogły wykorzystać ten kod C++.

  1. Utwórz folder shared na tym samym poziomie co foldery android i ios.

  2. Wewnątrz folderu shared utwórz nowy plik NativeSampleModule.h.

    shared/NativeSampleModule.h
    #pragma once

    #include <AppSpecsJSI.h>

    #include <memory>
    #include <string>

    namespace facebook::react {

    class NativeSampleModule : public NativeSampleModuleCxxSpec<NativeSampleModule> {
    public:
    NativeSampleModule(std::shared_ptr<CallInvoker> jsInvoker);

    std::string reverseString(jsi::Runtime& rt, std::string input);
    };

    } // namespace facebook::react

  3. Wewnątrz folderu shared utwórz nowy plik NativeSampleModule.cpp.

    shared/NativeSampleModule.cpp
    #include "NativeSampleModule.h"

    namespace facebook::react {

    NativeSampleModule::NativeSampleModule(std::shared_ptr<CallInvoker> jsInvoker)
    : NativeSampleModuleCxxSpec(std::move(jsInvoker)) {}

    std::string NativeSampleModule::reverseString(jsi::Runtime& rt, std::string input) {
    return std::string(input.rbegin(), input.rend());
    }

    } // namespace facebook::react

Przyjrzyjmy się utworzonym plikom:

  • Plik NativeSampleModule.h to plik nagłówkowy czystego modułu Turbo w C++. Dyrektywy include zapewniają, że dołączamy specyfikacje generowane przez Codegen, zawierające interfejs i klasę bazową do implementacji.

  • Moduł znajduje się w przestrzeni nazw facebook::react, aby mieć dostęp do wszystkich typów w niej zdefiniowanych.

  • Klasa NativeSampleModule jest faktycznym modułem Turbo Native i rozszerza klasę NativeSampleModuleCxxSpec, która zawiera kod pomocniczy i standardowy, umożliwiający tej klasie działanie jako moduł Turbo Native.

  • Na koniec mamy konstruktor, który przyjmuje wskaźnik do CallInvoker do komunikacji z JS w razie potrzeby, oraz prototyp funkcji, którą musimy zaimplementować.

Plik NativeSampleModule.cpp zawiera właściwą implementację naszego modułu Turbo Native oraz implementuje konstruktor i metodę zadeklarowaną w specyfikacji.

4. Rejestracja modułu na platformie​

Kolejne kroki umożliwią nam zarejestrowanie modułu na platformie. To właśnie ten krok udostępnia natywny kod w JS, dzięki czemu aplikacja React Native może wywoływać metody natywne z warstwy JavaScript.

To jedyny moment, w którym będziemy musieli napisać kod specyficzny dla platformy.

Android​

Aby zapewnić poprawne zbudowanie modułu Turbo Native w C++ w aplikacji Android, musimy:

  1. Utworzyć plik CMakeLists.txt dla dostępu do naszego kodu C++.

  2. Zmodyfikować build.gradle, aby wskazywał na nowo utworzony plik CMakeLists.txt.

  3. Utworzyć plik OnLoad.cpp w naszej aplikacji Android do rejestracji nowego modułu Turbo Native.

1. Utworzenie pliku CMakeLists.txt​

Android używa CMake do budowania. CMake potrzebuje dostępu do plików zdefiniowanych w naszym folderze shared.

  1. Utwórz nowy folder SampleApp/android/app/src/main/jni. Folder jni to miejsce, gdzie znajduje się część C++ w Androidzie.

  2. Utwórz plik CMakeLists.txt i dodaj następującą zawartość:

CMakeLists.txt
cmake_minimum_required(VERSION 3.13)

# Define the library name here.
project(appmodules)

# This file includes all the necessary to let you build your React Native application
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

# Define where the additional source code lives. We need to crawl back the jni, main, src, app, android folders
target_sources(${CMAKE_PROJECT_NAME} PRIVATE ../../../../../shared/NativeSampleModule.cpp)

# Define where CMake can find the additional header files. We need to crawl back the jni, main, src, app, android folders
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ../../../../../shared)

Plik CMake wykonuje następujące czynności:

  • Definiuje bibliotekę appmodules, gdzie zostanie dołączony cały kod C++ aplikacji.

  • Ładuje bazowy plik CMake React Native.

  • Dodaje źródłowy kod C++ modułu za pomocą dyrektyw target_sources. Domyślnie React Native wypełnia bibliotekę appmodules standardowymi źródłami – tutaj dodajemy nasz niestandardowy moduł. Zauważ, że musimy cofnąć się z folderu jni do folderu shared, gdzie znajduje się nasz moduł Turbo w C++.

  • Określa, gdzie CMake może znaleźć pliki nagłówkowe modułu. Również w tym przypadku musimy cofnąć się z folderu jni.

2. Modyfikacja build.gradle do uwzględnienia niestandardowego kodu C++​

Gradle to narzędzie orchestrujące budowanie w Androidzie. Musimy wskazać mu, gdzie znajdują się pliki CMake do zbudowania modułu Turbo Native.

  1. Otwórz plik SampleApp/android/app/build.gradle.

  2. Dodaj następujący blok w pliku Gradle, wewnątrz istniejącej sekcji android:

android/app/build.gradle
    buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}

+ externalNativeBuild {
+ cmake {
+ path "src/main/jni/CMakeLists.txt"
+ }
+ }
}

Ten blok wskazuje plikowi Gradle, gdzie szukać pliku CMake. Ścieżka jest względna względem lokalizacji pliku build.gradle, więc musimy dodać ścieżkę do plików CMakeLists.txt w folderze jni.

3. Rejestracja nowego modułu Turbo Native​

Ostatnim krokiem jest zarejestrowanie nowego modułu Turbo Native w C++ w środowisku uruchomieniowym, aby gdy JS zażąda modułu, aplikacja wiedziała, gdzie go znaleźć.

  1. Z folderu SampleApp/android/app/src/main/jni wykonaj polecenie:
shell
curl -O https://raw.githubusercontent.com/facebook/react-native/v0.78.0/packages/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp
  1. Następnie zmodyfikuj ten plik w następujący sposób:
android/app/src/main/jni/OnLoad.cpp
#include <DefaultComponentsRegistry.h>
#include <DefaultTurboModuleManagerDelegate.h>
#include <autolinking.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <rncore.h>

+ // Include the NativeSampleModule header
+ #include <NativeSampleModule.h>

//...

std::shared_ptr<TurboModule> cxxModuleProvider(
const std::string& name,
const std::shared_ptr<CallInvoker>& jsInvoker) {
// Here you can provide your CXX Turbo Modules coming from
// either your application or from external libraries. The approach to follow
// is similar to the following (for a module called `NativeCxxModuleExample`):
//
// if (name == NativeCxxModuleExample::kModuleName) {
// return std::make_shared<NativeCxxModuleExample>(jsInvoker);
// }

+ // This code registers the module so that when the JS side asks for it, the app can return it
+ if (name == NativeSampleModule::kModuleName) {
+ return std::make_shared<NativeSampleModule>(jsInvoker);
+ }

// And we fallback to the CXX module providers autolinked
return autolinking_cxxModuleProvider(name, jsInvoker);
}

// leave the rest of the file

Te kroki pobierają oryginalny plik OnLoad.cpp z React Native, abyśmy mogli bezpiecznie go nadpisać i załadować moduł Turbo Native w języku C++ w aplikacji.

Po pobraniu pliku możemy go zmodyfikować poprzez:

  • Dołączenie pliku nagłówkowego wskazującego na nasz moduł

  • Zarejestrowanie modułu Turbo Native, aby aplikacja mogła go zwrócić, gdy zostanie zażądany przez JS.

Teraz możesz uruchomić yarn android z katalogu głównego projektu, aby zobaczyć pomyślne zbudowanie aplikacji.

iOS​

Aby upewnić się, że aplikacja iOS poprawnie zbuduje moduł Turbo Native w języku C++, musimy:

  1. Zainstalować pody i uruchomić Codegen.

  2. Dodać folder shared do naszego projektu iOS.

  3. Zarejestrować moduł Turbo Native w języku C++ w aplikacji.

1. Instalacja Podów i uruchomienie Codegen​

Pierwszym krokiem są standardowe czynności wykonywane przy przygotowaniu aplikacji iOS. CocoaPods to narzędzie służące do konfiguracji i instalacji zależności React Native, które dodatkowo uruchomi dla nas Codegen.

cd ios
bundle install
bundle exec pod install

2. Dodanie folderu shared do projektu iOS​

Ten krok dodaje folder shared do projektu, aby był widoczny w Xcode.

  1. Otwórz przestrzeń roboczą Xcode wygenerowaną przez CocoaPods.
cd ios
open SampleApp.xcworkspace
  1. Kliknij projekt SampleApp po lewej stronie i wybierz Add files to "Sample App"....

Dodaj pliki do aplikacji Sample App...

  1. Wybierz folder shared i kliknij Add.

Dodaj pliki do aplikacji Sample App...

Jeśli wszystko wykonałeś poprawnie, twój projekt po lewej stronie powinien wyglądać następująco:

Projekt w Xcode

3. Rejestracja modułu Turbo Native w języku C++ w aplikacji​

ostrzeżenie

Jeśli Twoja aplikacja zawiera moduły lokalne napisane w C++, nie będziesz mógł użyć dostarczonego w React Native 0.77 AppDelegate w Swift.

Jeśli Twoja aplikacja należy do tej kategorii, pomiń migrację AppDelegate do Swift i kontynuuj używanie Objective-C++ dla AppDelegate swojej aplikacji.

Rdzeń React Native jest głównie rozwijany w C++, aby umożliwić współdzielenie kodu między iOS, Androidem i innymi platformami. Interoperacyjność między Swift a C++ nie jest jeszcze dojrzała ani stabilna. Pracujemy nad sposobami wypełnienia tej luki, abyś także mógł migrować do Swift.

W tym ostatnim kroku wskażemy aplikacji iOS, gdzie szukać czystego modułu Turbo Native w C++.

W Xcode otwórz plik AppDelegate.mm i zmodyfikuj go następująco:

SampleApp/AppDelegate.mm
#import <React/RCTBundleURLProvider.h>
+ #import <RCTAppDelegate+Protected.h>
+ #import "NativeSampleModule.h"

// ...
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

+- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
+ jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
+{
+ if (name == "NativeSampleModule") {
+ return std::make_shared<facebook::react::NativeSampleModule>(jsInvoker);
+ }
+
+ return [super getTurboModule:name jsInvoker:jsInvoker];
+}

@end

Te zmiany realizują kilka rzeczy:

  1. Importowanie nagłówka RCTAppDelegate+Protected, aby AppDelegate widział, że jest zgodny z protokołem RCTTurboModuleManagerDelegate.

  2. Importowanie interfejsu czystego modułu Turbo Native w C++ NativeSampleModule.h.

  3. Nadpisanie metody getTurboModule dla modułów C++, tak aby gdy strona JS zażąda modułu o nazwie NativeSampleModule, aplikacja wiedziała, który moduł zwrócić.

Jeśli teraz zbudujesz aplikację w Xcode, proces powinien zakończyć się powodzeniem.

5. Testowanie kodu​

Czas uzyskać dostęp do naszego modułu Turbo Native w C++ z poziomu JS. W tym celu musimy zmodyfikować plik App.tsx, aby zaimportować moduł Turbo Native i wywołać go w naszym kodzie.

  1. Otwórz plik App.tsx.

  2. Zastąp zawartość szablonu następującym kodem:

App.tsx
import React from 'react';
import {
Button,
SafeAreaView,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
import SampleTurboModule from './specs/NativeSampleModule';

function App(): React.JSX.Element {
const [value, setValue] = React.useState('');
const [reversedValue, setReversedValue] = React.useState('');

const onPress = () => {
const revString = SampleTurboModule.reverseString(value);
setReversedValue(revString);
};

return (
<SafeAreaView style={styles.container}>
<View>
<Text style={styles.title}>
Welcome to C++ Turbo Native Module Example
</Text>
<Text>Write down here the text you want to reverse</Text>
<TextInput
style={styles.textInput}
placeholder="Write your text here"
onChangeText={setValue}
value={value}
/>
<Button title="Reverse" onPress={onPress} />
<Text>Reversed text: {reversedValue}</Text>
</View>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 18,
marginBottom: 20,
},
textInput: {
borderColor: 'black',
borderWidth: 1,
borderRadius: 5,
padding: 10,
marginTop: 10,
},
});

export default App;

Najważniejsze fragmenty w tej aplikacji to:

  • import SampleTurboModule from './specs/NativeSampleModule';: ta linia importuje moduł Turbo Native do aplikacji,

  • const revString = SampleTurboModule.reverseString(value); w callbacku onPress: w ten sposób możesz używać modułu Turbo Native w swojej aplikacji.

ostrzeżenie

Dla uproszczenia tego przykładu bezpośrednio zaimportowaliśmy plik specyfikacji w naszej aplikacji. Najlepszą praktyką w tym przypadku jest utworzenie osobnego pliku opakowującego specyfikacje i użycie go w aplikacji. Daje to możliwość przygotowania danych wejściowych dla specyfikacji i zapewnia większą kontrolę nad nimi w JS.

Gratulacje! Właśnie stworzyłeś swój pierwszy moduł Turbo Native w C++!

Android
iOS
Android Video
iOS video