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.

bash
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.
bash
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