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

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.82.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​

Aby zarejestrować czysty moduł Turbo Native w języku C++ w swojej aplikacji, musisz:

  1. Utworzyć ModuleProvider dla modułu natywnego

  2. Skonfigurować package.json, aby powiązać nazwę modułu JS z klasą ModuleProvider.

ModuleProvider to plik Objective-C++, który łączy czysty moduł C++ z resztą aplikacji iOS.

3.1 Tworzenie ModuleProvider​
  1. W Xcode wybierz projekt SampleApp i naciśnij ⌘ + N, aby utworzyć nowy plik.

  2. Wybierz szablon Cocoa Touch Class.

  3. Wprowadź nazwę NativeSampleModuleProvider (pozostaw pozostałe pola jako Subclass of: NSObject i Language: Objective-C)

  4. Kliknij Next, aby wygenerować pliki.

  5. Zmień nazwę pliku NativeSampleModuleProvider.m na NativeSampleModuleProvider.mm. Rozszerzenie mm oznacza plik Objective-C++.

  6. Zaimplementuj zawartość pliku NativeSampleModuleProvider.h następująco:

NativeSampleModuleProvider.h

#import <Foundation/Foundation.h>
#import <ReactCommon/RCTTurboModule.h>

NS_ASSUME_NONNULL_BEGIN

@interface NativeSampleModuleProvider : NSObject <RCTModuleProvider>

@end

NS_ASSUME_NONNULL_END

To deklaruje obiekt NativeSampleModuleProvider zgodny z protokołem RCTModuleProvider.

  1. Zaimplementuj zawartość pliku NativeSampleModuleProvider.mm następująco:
NativeSampleModuleProvider.mm

#import "NativeSampleModuleProvider.h"
#import <ReactCommon/CallInvoker.h>
#import <ReactCommon/TurboModule.h>
#import "NativeSampleModule.h"

@implementation NativeSampleModuleProvider

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeSampleModule>(params.jsInvoker);
}

@end

Ten kod implementuje protokół RCTModuleProvider, tworząc czysty moduł C++ NativeSampleModule podczas wywołania metody getTurboModule:.

3.2 Aktualizacja pliku package.json​

Ostatni krok polega na aktualizacji pliku package.json, aby poinformować React Native o powiązaniu między specyfikacją JS modułu natywnego a konkretną implementacją tych specyfikacji w kodzie natywnym.

Zmodyfikuj plik package.json w następujący sposób:

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

"dependencies": {

W tym momencie należy ponownie zainstalować pakiety CocoaPods, aby upewnić się, że Codegen zostanie uruchomiony ponownie i wygeneruje nowe pliki:

# from the ios folder
bundle exec pod install
open SampleApp.xcworkspace

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