Native Module
Architekturbewertung erforderlich: Diese Dokumentation wurde zur Unterstützung der Entwicklung gegen die "alte" oder "Legacy"-Architektur von React Native geschrieben. Sie ist möglicherweise nicht direkt auf die Entwicklung mit der neuen Architektur anwendbar und muss überprüft und möglicherweise aktualisiert werden. Informationen zu React Native-Architekturen in React Native Windows finden Sie unter Neu vs. Alt Architektur.
Die neuesten Informationen zur nativen Entwicklung unter Windows finden Sie unter Native Plattform: Übersicht.
Diese Dokumentation und der zugrunde liegende Plattformcode sind in Arbeit. Beispiele (C# und C++/WinRT):
Manchmal benötigt eine App Zugriff auf eine Plattform-API, für die React Native noch kein entsprechendes Modul hat. Vielleicht möchten Sie vorhandenen .NET-Code wiederverwenden, ohne ihn in JavaScript neu implementieren zu müssen, oder Sie möchten hochperformanten, multithreaded Code für Bildverarbeitung, eine Datenbank oder eine beliebige Anzahl fortgeschrittener Erweiterungen schreiben.
React Native wurde so konzipiert, dass Sie echten nativen Code schreiben und auf die volle Leistung der Plattform zugreifen können. Dies ist eine fortgeschrittene Funktion, und wir erwarten nicht, dass sie Teil des üblichen Entwicklungsprozesses ist, aber es ist unerlässlich, dass sie existiert. Wenn React Native ein benötigtes natives Feature nicht unterstützt, sollten Sie in der Lage sein, es selbst zu erstellen.
HINWEIS: Wenn Sie ein Widget mit einer UI-Komponente erstellen, lesen Sie die Anleitung zu den nativen UI-Komponenten.
Übersicht
Native Module enthalten (oder wrappen) nativen Code, der dann für JS zugänglich gemacht werden kann. Um dies in React Native for Windows zu erreichen, müssen Sie auf hoher Ebene Folgendes tun:
- Erstellen Sie Ihr natives Modul, die Klasse, die Ihren nativen Code aufruft.
- Fügen Sie der Klasse benutzerdefinierte Attribute hinzu. Diese Attribute ermöglichen es Ihnen, Methoden, Eigenschaften, Konstanten und Ereignisse zu definieren, auf die von JavaScript aus verwiesen werden kann.
- Registrieren Sie Ihr natives Modul. Beachten Sie, dass in Ihrer App definierte native Module automatisch registriert werden.
- Fügen Sie das Paket Ihrer React Native-Anwendung hinzu.
- Verwenden Sie Ihr natives Modul aus Ihrem JavaScript-Code.
React Native for Windows unterstützt die Erstellung nativer Module sowohl in C# als auch in C++. Beispiele für beide finden Sie unten. Weitere Informationen zur Wahl zwischen C++ und C# für nativen Code finden Sie im Hinweis zur Auswahl von C++ oder C# für nativen Code.
HINWEIS: Wenn Sie den auf Reflexion basierenden Annotationsansatz nicht verwenden können, können Sie native Module direkt über die ABI definieren. Dies wird im Dokument Schreiben von nativen Modulen ohne Verwendung von Attributen beschrieben.
Initial Setup
Folgen Sie der Anleitung zur Einrichtung nativer Module, um die Visual Studio-Infrastruktur für die Erstellung Ihres eigenen eigenständigen nativen Moduls für React Native Windows einzurichten.
Sobald Sie Ihre Entwicklungsumgebung und Projektstruktur eingerichtet haben, sind Sie bereit, Code zu schreiben.
Öffnen Sie die Visual Studio-Projektmappe im Ordner windows und fügen Sie die neuen Dateien direkt zum App-Projekt hinzu.
Sample Native Module
1. Konfigurieren Sie Windows-Codegenerierung in package.json
Fügen Sie das folgende Objekt zur package.json-Datei Ihres Pakets hinzu
"codegenConfig": {
"name": "NameOfYourApp",
"type": "modules",
"jsSrcsDir": "src",
"windows": {
"namespace": "YourAppCodegenNamespace",
"cppStringType": "std::string", /* optional */
"separateDataTypes": false, /* optional */
"outputDirectory": "codegen" /* optional */
}
},
Die Werte für name, type und jsSrcsDir werden mit react-native geteilt, wie hier dokumentiert. Das windows-Objekt veranlasst die windows-codegen-Aufgabe, Windows-spezifische Codegenerierung für alle TurboModule-Spec-Dateien zu generieren, die in Ihrem Projekt definiert sind.
windows.namespace: Erforderlich. Diese Eigenschaft steuert, welchen C++-Namespace diese generierten Dateien verwenden.windows.cppStringType: Optional. Diese Eigenschaft steuert, welcher C++-Zeichenketten-Typ in den generierten Dateien verwendet wird. Der Standardwert iststd::string. Sie können zwischenstd::stringundstd::wstringwählen.windows.separateDataTypes: Optional.- Der Standardwert ist
false. In diesem Fall wirdNativeAbcSpec.g.hausNativeAbc.tsoder mit einer anderen erkannten Dateiendung generiert. - Wenn er
trueistNativeAbcDataTypes.hundNativeAbcSpec.g.hwerden generiert.NativeAbcDataTypes.henthält alle benutzerdefinierten Typen, die inNativeAbc.tsdefiniert sind.NativeAbcSpec.g.henthält den gesamten restlichen Code.NativeAbcSpec.g.hschließtNativeAbcDataTypes.hnicht ein.- Wenn es keine benutzerdefinierten Typen gibt, wird
NativeAbcDataTypes.hnicht generiert, auch wennwindows.separateDataTypesauftruegesetzt ist.
- Der Standardwert ist
windows.outputDirectory: Optional. Diese Eigenschaft steuert, wo die generierten Dateien gespeichert werden. Der Standardwert istcodegen, was bedeutet, dass die Dateien im Ordnercodegenunter dem Arbeitsverzeichnis abgelegt werden. Wenn ein solcher Ordner zu diesem Zeitpunkt nicht existiert, wird er erstellt.
2. Erstellen Sie eine JavaScript-Spezifikation
Module sollten eine Definition haben, die in einer typisierten JavaScript-Variante (TypeScript oder Flow) definiert ist. Codegenerierung verwendet diese Spezifikationen, um die von Ihrem nativen Code bereitgestellte Schnittstelle zu überprüfen.
Die Datei, die diese Spezifikation enthält, muss zwei Anforderungen erfüllen:
- Die Datei **muss**
Native<MODULE_NAME>heißen und mit einer.js- oder.jsx-Erweiterung bei Verwendung von Flow oder mit einer.ts- oder.tsx-Erweiterung bei Verwendung von TypeScript. - Die Datei **muss** ein
TurboModuleRegistrySpec-Objekt exportieren.
Beispiel-Spezifikationsdatei NativeFancyMath.ts
import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
getConstants() : {
E: number,
Pi: number,
};
add(a: number, b: number, callback: (value: number) => void) : void;
}
export default TurboModuleRegistry.get<Spec>(
'FancyMath'
) as Spec | null;
Beachten Sie, dass diese Datei zwar
TurboModuleRegistryverwendet, native Module jedoch weiterhin mit diesem JavaScript funktionieren. Der Code ist zukunftsorientiert und unterstützt sowohl native Module als auch TurboModules.
Attribute
| Attribut | Verwenden Sie |
|---|---|
ReactModule | Gibt an, dass die Klasse ein natives Modul ist. |
ReactMethod | Gibt eine asynchrone Methode an. |
ReactSyncMethod | Gibt eine synchrone Methode an. |
ReactConstant | Gibt ein Feld oder eine Eigenschaft an, das eine Konstante darstellt. |
ReactConstantProvider | Gibt eine Methode an, die eine Reihe von Konstanten bereitstellt. |
ReactEvent | Gibt ein Feld oder eine Eigenschaft an, das ein Ereignis darstellt. |
ReactStruct | Gibt eine struct an, die in nativen Methoden verwendet werden kann. |
ReactInit | Gibt ein Initialisierungsmodul für die Klasse an. |
ReactFunction | Gibt eine JavaScript-Funktion an, die Sie Ihrem nativen Code zur Verfügung stellen möchten. |
3. Erstellen Ihres nativen Moduls
Hier ist ein Beispiel für ein natives Modul in C# namens FancyMath. Es ist eine einfache Klasse, die zwei numerische Konstanten und eine Methode namens 'add' definiert.
FancyMath.cs:
using System;
using Microsoft.ReactNative.Managed;
namespace NativeModuleSample
{
[ReactModule]
class FancyMath
{
[ReactConstant]
public double E = Math.E;
[ReactConstant("Pi")]
public double PI = Math.PI;
[ReactMethod("add")]
public double Add(double a, double b)
{
double result = a + b;
AddEvent(result);
return result;
}
[ReactEvent]
public ReactEvent<double> AddEvent { get; set; }
}
}
Zuerst sehen Sie, dass wir die gemeinsam genutzte Bibliothek Microsoft.ReactNative.Managed verwenden, die die einfachste (und empfohlene) Erfahrung für die Erstellung nativer Module bietet. Microsoft.ReactNative.Managed stellt den Mechanismus bereit, der die Annotationen nativer Module erkennt, um zur Laufzeit Bindungen zu erstellen.
Das Attribut [ReactModule] besagt, dass die Klasse ein React Native natives Modul ist. Es hat einen optionalen Parameter für den Namen des Moduls, der für JavaScript sichtbar ist, und optional den Namen eines registrierten Event-Emitters. Standardmäßig ist der für JavaScript sichtbare Name derselbe wie der Klassenname, und der Standard-Event-Emitter ist RCTDeviceEventEmitter.
Sie können den JavaScript-Modulnamen wie folgt überschreiben: [ReactModule("math")].
Sie können einen anderen Event-Emitter angeben, z. B.: [ReactModule(EventEmitter = "mathEmitter")].
HINWEIS: Bei Verwendung des Standard-Event-Emitters
RCTDeviceEventEmittermüssen alle nativen Event-Namen **global eindeutig über alle nativen Module** (auch die in RN integrierten) sein. Die Angabe eines eigenen Event-Emitters bedeutet jedoch, dass Sie diesen ebenfalls erstellen und registrieren müssen. Dieser Prozess ist im Dokument Native Modules and React Native Windows (Advanced Topics) beschrieben.
Das Attribut [ReactConstant] dient zur Definition von Konstanten. Hier hat FancyMath zwei Konstanten definiert: E und Pi. Beim Zugriff auf diese Konstanten sollten Sie FancyMath.getConstants().E verwenden. Wenn Sie in JS einen anderen Namen verwenden möchten, könnten Sie den JS-Namen wie folgt überschreiben: [ReactConstant("e")].
Das Attribut [ReactMethod] dient zur Definition von Methoden. In FancyMath haben wir eine Methode, add, die zwei Doubles entgegennimmt und ihre Summe zurückgibt. Wie zuvor können Sie den Namen optional anpassen, z. B.: [ReactMethod("add")].
Das Attribut [ReactEvent] dient zur Definition von Ereignissen. In FancyMath haben wir ein Ereignis, AddEvent, das den ReactEvent<double>-Delegaten verwendet, wobei das Double den Typ der Ereignisdaten darstellt. Immer wenn wir den AddEvent-Delegaten in unserem nativen Code aufrufen (wie oben geschehen), wird in JavaScript ein Ereignis namens "AddEvent" ausgelöst. Wie zuvor könnten Sie den Namen in JS optional wie folgt angepasst haben: [ReactEvent("addEvent")].
4. Registrierung Ihres nativen Moduls
WICHTIGER HINWEIS: Wenn Sie ein neues Projekt über die CLI erstellen, registriert die generierte Klasse
ReactApplicationautomatisch alle nativen Module, die innerhalb der App definiert sind. **Sie müssen native Module, die im Geltungsbereich Ihrer App definiert sind, nicht manuell registrieren, da sie automatisch registriert werden.**
Nun möchten wir unser neues FancyMath-Modul bei React Native registrieren, damit wir es aus dem JavaScript-Code verwenden können. Dazu erstellen wir zunächst einen ReactPackageProvider, der Microsoft.ReactNative.IReactPackageProvider implementiert.
ReactPackageProvider.cs:
using Microsoft.ReactNative.Managed;
namespace NativeModuleSample
{
public sealed class ReactPackageProvider : IReactPackageProvider
{
public void CreatePackage(IReactPackageBuilder packageBuilder)
{
packageBuilder.AddAttributedModules();
}
}
}
Hier haben wir die Methode CreatePackage implementiert, die den packageBuilder erhält, um den Inhalt des Pakets zu erstellen. Da wir Reflexion verwenden, um native Module zu entdecken und zu binden, rufen wir die Erweiterungsmethode AddAttributedModules auf, um alle nativen Module in unserer Assembly zu registrieren, die das ReactModule-Attribut haben.
Jetzt, da wir den ReactPackageProvider haben, ist es an der Zeit, ihn in unserer ReactApplication zu registrieren. Dies geschieht einfach durch Hinzufügen des Providers zur Eigenschaft PackageProviders.
App.xaml.cs:
using Microsoft.ReactNative;
namespace SampleApp
{
sealed partial class App : ReactApplication
{
public App()
{
/* Other Init Code */
PackageProviders.Add(new Microsoft.ReactNative.Managed.ReactPackageProvider()); // Includes any modules in this project
PackageProviders.Add(new NativeModuleSample.ReactPackageProvider());
/* Other Init Code */
}
}
}
Dieses Beispiel geht davon aus, dass sich der oben erstellte NativeModuleSample.ReactPackageProvider in einem anderen Projekt (Assembly) als unserer Anwendung befindet. Sie werden jedoch feststellen, dass wir standardmäßig auch einen Microsoft.ReactNative.Managed.ReactPackageProvider hinzugefügt haben.
Der Microsoft.ReactNative.Managed.ReactPackageProvider ist eine Erleichterung, die sicherstellt, dass alle nativen Module und View Manager, die im App-Projekt definiert sind, automatisch registriert werden. Wenn Sie also Ihre nativen Module direkt im App-Projekt erstellen, möchten Sie keinen separaten ReactPackageProvider definieren.
Attribute
| Attribut | Verwenden Sie |
|---|---|
REACT_MODULE | Gibt an, dass die Klasse ein natives Modul ist, wodurch dieses Modul von der Funktion AddAttributedModules erkannt wird. |
REACT_MODULE_NOREG | Gibt an, dass die Klasse ein natives Modul ist. |
REACT_METHOD | Gibt eine asynchrone Methode an. |
REACT_SYNC_METHOD | Gibt eine synchrone Methode an. |
REACT_GET_CONSTANTS | Gibt eine Methode an, die eine Reihe von Konstanten bereitstellt. (Bevorzugt) |
REACT_CONSTANT | Gibt ein Feld oder eine Eigenschaft an, das eine Konstante darstellt. |
REACT_CONSTANTPROVIDER | Gibt eine Methode an, die eine Reihe von Konstanten bereitstellt. |
REACT_EVENT | Gibt ein Feld oder eine Eigenschaft an, das ein Ereignis darstellt. |
REACT_STRUCT | Gibt eine struct an, die in nativen Methoden verwendet werden kann (verschachteln Sie die Definition nicht innerhalb von REACT_MODULE). |
REACT_INIT | Gibt ein Initialisierungsmodul für die Klasse an. |
ReactFunction | Gibt eine JavaScript-Funktion an, die Sie Ihrem nativen Code zur Verfügung stellen möchten. |
3. Erstellen Ihres nativen Moduls
Hier ist ein Beispiel für ein natives Modul in C++ namens FancyMath. Es ist eine einfache Klasse, die zwei numerische Konstanten und eine Methode namens 'add' definiert.
FancyMath.h:
#pragma once
#include "pch.h"
#include <codegen\FancyMathSpec.g.h> // This file will be generated by the windows-codegen command from your js spec file
#include <functional>
#define _USE_MATH_DEFINES
#include <math.h>
#include "NativeModules.h"
namespace NativeModuleSample
{
REACT_MODULE(FancyMath);
struct FancyMath
{
// The namespace here will align with the codegenConfig.windows.namespace property in your package.json
using ModuleSpec = YourAppCodegenNamespace::FancyMathSpec;
REACT_GET_CONSTANTS(GetConstants)
SampleLibraryCodegen::FancyMathSpec_Constants GetConstants() noexcept {
SampleLibraryCodegen::FancyMathSpec_Constants constants;
constants.E = M_E;
constants.Pi = M_PI;
return constants;
}
REACT_METHOD(Add, L"add");
double Add(double a, double b) noexcept
{
double result = a + b;
AddEvent(result);
return result;
}
REACT_EVENT(AddEvent);
std::function<void(double)> AddEvent;
};
}
Das Makro-Attribut REACT_MODULE besagt, dass die Klasse ein React Native natives Modul ist. Es erhält den Klassennamen als ersten Parameter. Alle anderen Makro-Attribute erhalten ebenfalls ihr Ziel als ersten Parameter. REACT_MODULE hat einen optionalen Parameter für den Namen des Moduls, der für JavaScript sichtbar ist, und optional den Namen eines registrierten Event-Emitters. Standardmäßig ist der für JavaScript sichtbare Name derselbe wie der Klassenname, und der Standard-Event-Emitter ist RCTDeviceEventEmitter.
Es ist wichtig, die ModuleSpec anzugeben. Die Definition von ModuleSpec erzwingt, dass Ihr Modul dieselben Methoden wie die JS-Spec-Datei definiert.
HINWEIS: Methoden, die mit
REACT_METHODund ähnlichen annotiert sind, müssen dennoexcept-Spezifizierer haben, sonst wird das Programm nicht kompiliert. Modulautoren sollten sicherstellen, dass alle Ausnahmen innerhalb der Methode behandelt werden.
Sie können den JavaScript-Modulnamen wie folgt überschreiben: REACT_MODULE(FancyMath, L"math").
Sie können einen anderen Event-Emitter angeben, z. B.: REACT_MODULE(FancyMath, L"math", L"mathEmitter").
HINWEIS: Bei Verwendung des Standard-Event-Emitters
RCTDeviceEventEmittermüssen alle nativen Event-Namen **global eindeutig über alle nativen Module** (auch die in RN integrierten) sein. Die Angabe eines eigenen Event-Emitters bedeutet jedoch, dass Sie diesen ebenfalls erstellen und registrieren müssen. Dieser Prozess ist im Dokument Native Modules and React Native Windows (Advanced Topics) beschrieben.
Dann definieren wir Konstanten, dies geschieht mit dem Makro-Attribut REACT_GET_CONSTANTS. In diesem Fall geben wir eine Struktur zurück, die mit REACT_STRUCT definiert wurde. Dies generiert Code, um die Struktur automatisch in ein JSValueObject zu übersetzen.
Es ist genauso einfach, benutzerdefinierte Methoden hinzuzufügen, indem Sie eine öffentliche Methode mit REACT_METHOD attributieren. In FancyMath haben wir eine Methode, add, die zwei Doubles entgegennimmt und ihre Summe zurückgibt. Auch hier haben wir das optionale Argument name im Makro-Attribut REACT_METHOD angegeben, sodass wir in JS add anstelle von Add aufrufen.
Native Module können nicht überprüfen, ob die Parametertypen und die Anzahl der Parameter zwischen dem, was aus JavaScript aufgerufen wird, und dem, was der native Code akzeptiert, übereinstimmen. Das Framework validiert jedoch, dass die Anzahl der Promise-ähnlichen Parameter übereinstimmt: Wenn die JavaScript-API async ist, wird erwartet, dass in der Signatur der nativen Methodenimplementierung ein "Promise-ähnlicher" Parameter vorhanden ist.
Ein "Promise-ähnlicher" Parameter ist entweder
React::ReactPromise<T>- eine Callback-Funktion oder ein Funktor.
Siehe Verwendung von asynchronen Windows-APIs.
Hier ist ein Beispiel für eine async-Methode, die einen String zurückgibt
REACT_METHOD(GetString, L"getString");
void GetString(React::ReactPromise<std::string>&& result) noexcept
{
if (error) {
result.Reject("Failure");
} else {
std::string text = DoSomething();
result.Resolve(text);
}
}
Dies kann auch mit C++/WinRT-Ereignishandlern oder IAsyncOperation<T> verknüpft werden, wie hier gezeigt
REACT_METHOD(GetString, L"getString");
void GetString(React::ReactPromise<std::string>&& result) noexcept
{
if (error) {
result.Reject("Failure");
} else {
something.Completed([result] (const auto& operation, const auto& status) {
// do error checking, e.g. status should be Completed
winrt::hstring result{operation.GetResults()};
result.Resolve(winrt::to_string(result));
});
}
}
Weitere Details finden Sie unter JavaScript und Windows Runtime-Zeichenketten.
Der Typ JSValue kann verwendet werden, wenn die API ein JavaScript-Objekt zurückgibt oder JavaScript-Objekte als Eingabeparameter entgegennimmt.
Native Module sollten REACT_METHOD anstelle von REACT_SYNC_METHOD verwenden, da letzteres das Web-Debugging ausschließt und Leistungseinbußen hat. Beim Web-Debugging sehen Sie eine Ausnahme wie: Calling synchronous methods on native modules is not supported in Chrome. Consider providing alternative to expose this method in debug mode, e.g. by exposing constants ahead-of-time Siehe: MessageQueue.js.
Um benutzerdefinierte Ereignisse hinzuzufügen, attributieren wir einen std::function<void(double)>-Delegaten mit REACT_EVENT, wobei das Double den Typ der Ereignisdaten darstellt. Immer wenn wir den AddEvent-Delegaten in unserem nativen Code aufrufen (wie oben geschehen), wird in JavaScript ein Ereignis namens "AddEvent" ausgelöst. Wie zuvor könnten Sie den Namen in JS optional wie folgt angepasst haben: REACT_EVENT(AddEvent, "addEvent").
4. Registrierung Ihres nativen Moduls
WICHTIGER HINWEIS: Wenn Sie ein neues Projekt über die CLI erstellen, registriert die generierte Klasse
ReactApplicationautomatisch alle nativen Module, die innerhalb der App definiert sind. **Sie müssen native Module, die im Geltungsbereich Ihrer App definiert sind, nicht manuell registrieren, da sie automatisch registriert werden.**
Nun möchten wir unser neues FancyMath-Modul bei React Native registrieren, damit wir es aus dem JavaScript-Code verwenden können. Dazu erstellen wir zunächst einen ReactPackageProvider, der Microsoft.ReactNative.IReactPackageProvider implementiert. Es beginnt mit der Definition einer IDL-Datei (.idl).
ReactPackageProvider.idl:
namespace NativeModuleSample
{
[webhosthidden]
[default_interface]
runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
{
ReactPackageProvider();
};
}
Danach fügen wir die .h- und .cpp-Dateien hinzu
ReactPackageProvider.h:
#pragma once
#include "ReactPackageProvider.g.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::NativeModuleSample::implementation
{
struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider>
{
ReactPackageProvider() = default;
void CreatePackage(IReactPackageBuilder const& packageBuilder) noexcept;
};
}
namespace winrt::NativeModuleSample::factory_implementation
{
struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider, implementation::ReactPackageProvider> {};
}
ReactPackageProvider.cpp:
#include "pch.h"
#include "ReactPackageProvider.h"
#include "ReactPackageProvider.g.cpp"
#include <ModuleRegistration.h>
// NOTE: You must include the headers of your native modules here in
// order for the AddAttributedModules call below to find them.
#include "FancyMath.h"
namespace winrt::NativeModuleSample::implementation
{
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const& packageBuilder) noexcept
{
AddAttributedModules(packageBuilder, true);
}
}
Wenn REACT_MODULE_NOREG anstelle von REACT_MODULE verwendet wird, registriert AddAttributedModules dieses Modul nicht für Sie. Ein solches Modul sollte manuell registriert werden.
packageBuilder.AddTurboModule(L"FancyMath", MakeModuleProvider<NativeModuleSample::FancyMath>());
Hier haben wir die Methode CreatePackage implementiert, die packageBuilder erhält, um den Inhalt des Pakets zu erstellen. Da wir Makros und Templates verwenden, um native Module zu entdecken und zu binden, rufen wir die Funktion AddAttributedModules auf, um alle nativen Module in unserer DLL zu registrieren, die das Makro-Attribut REACT_MODULE haben. Das Angeben von true hier registriert alle nativen Module als TurboModules anstelle von Native Modules. Dies vermeidet zusätzliche Serialisierung, die bei Aufrufen von Native Modules auftritt. Wenn Sie aus irgendeinem Grund möchten, dass die Module weiterhin als Native Modules ausgeführt werden, können Sie hier false angeben.
Weitere Details zu TurboModules finden Sie unter Native Modules vs Turbo Modules.
Jetzt, da wir den ReactPackageProvider haben, ist es an der Zeit, ihn in unserer ReactApplication zu registrieren. Dies geschieht einfach durch Hinzufügen des Providers zur Eigenschaft PackageProviders.
App.cpp:
#include "pch.h"
#include "App.h"
#include "ReactPackageProvider.h"
#include "winrt/NativeModuleSample.h"
namespace winrt::SampleApp::implementation {
App::App() noexcept {
/* Other Init Code */
PackageProviders().Append(make<ReactPackageProvider>()); // Includes all modules in this project
PackageProviders().Append(winrt::NativeModuleSample::ReactPackageProvider());
/* Other Init Code */
}
} // namespace winrt::SampleApp::implementation
Dieses Beispiel geht davon aus, dass sich der oben erstellte NativeModuleSample::ReactPackageProvider in einem anderen Projekt (Assembly) als unserer Anwendung befindet. Sie werden jedoch feststellen, dass wir standardmäßig auch einen SampleApp::ReactPackageProvider hinzugefügt haben.
Der SampleApp::ReactPackageProvider ist eine Erleichterung, die sicherstellt, dass alle nativen Module und View Manager, die im App-Projekt definiert sind, automatisch registriert werden. Wenn Sie also Ihre nativen Module direkt im App-Projekt erstellen, möchten Sie keinen separaten ReactPackageProvider definieren.
JavaScript und Windows Runtime-Zeichenketten
Beachten Sie, dass JavaScript-Zeichenketten UTF8 (d. h. std::string) sind, WinRT-Zeichenketten jedoch UTF16 (d. h. winrt::hstring in C++/WinRT). Wenn Sie zwischen JavaScript und WinRT-APIs interagieren, müssen Sie zwischen diesen beiden Codierungen konvertieren. Siehe String-Handling in C++/WinRT, insbesondere winrt::to_string und winrt::to_hstring.
5. Verwenden Ihres nativen Moduls in JS
Jetzt haben wir ein natives Modul, das bei React Native Windows registriert ist. Wie greifen wir darauf in JS zu? Hier ist eine einfache RN-App
NativeModuleSample.js:
import React, { Component } from 'react';
import {
AppRegistry,
Alert,
Text,
View,
} from 'react-native';
import FancyMath from './NativeFancyMath'
import { NativeEventEmitter } from 'react-native';
const FancyMathEventEmitter = new NativeEventEmitter(FancyMath);
class NativeModuleSample extends Component {
componentDidMount() {
// Subscribing to FancyMath.AddEvent
FancyMathEventEmitter.addListener('AddEvent', eventHandler, this);
}
componentWillUnmount() {
// Unsubscribing from FancyMath.AddEvent
FancyMathEventEmitter.removeListener('AddEvent', eventHandler, this);
}
eventHandler(result) {
console.log("Event was fired with: " + result);
}
_onPressHandler() {
// Calling FancyMath.add method
FancyMath.add(
/* arg a */ FancyMath.getConstants().Pi,
/* arg b */ FancyMath.E,
/* callback */ function (result) {
Alert.alert(
'FancyMath',
`FancyMath says ${FancyMath.getConstants().Pi} + ${FancyMath.getConstants().E} = ${result}`,
[{ text: 'OK' }],
{cancelable: false});
});
}
render() {
return (
<View>
<Text>FancyMath says PI = {FancyMath.getConstants().Pi}</Text>
<Text>FancyMath says E = {FancyMath.getConstants().E}</Text>
<Button onPress={this._onPressHandler} title="Click me!"/>
</View>);
}
}
AppRegistry.registerComponent('NativeModuleSample', () => NativeModuleSample);
Um auf Ihre nativen Module zuzugreifen, müssen Sie aus Ihrer Spec-Datei importieren, in diesem Fall NativeFancyMath. Da unsere Module Ereignisse auslösen, importieren wir auch NativeEventEmitter.
Um auf unsere FancyMath-Konstanten zuzugreifen, können wir einfach FancyMath.getConstants().E und FancyMath.getConstants().Pi aufrufen.
Aufrufe von Methoden sind aufgrund der asynchronen Natur der JS-Engine etwas anders. Wenn die native Methode nichts zurückgibt, können wir die Methode einfach aufrufen. In diesem Fall gibt FancyMath.add() jedoch einen Wert zurück. Daher fügen wir zusätzlich zu den beiden notwendigen Parametern eine Callback-Funktion hinzu, die mit dem Ergebnis von FancyMath.add() aufgerufen wird. Im obigen Beispiel sehen wir, dass der Callback einen Alert-Dialog mit dem Ergebniswert auslöst.
Bei Ereignissen sehen Sie, dass wir eine Instanz von NativeEventEmitter erstellt haben, der unser FancyMath-Modul übergeben wurde, und sie FancyMathEventEmitter genannt haben. Wir können dann die Methoden FancyMathEventEmitter.addListener() und FancyMathEventEmitter.removeListener() verwenden, um uns für unser FancyMath.AddEvent anzumelden. In diesem Fall wird, wenn AddEvent im nativen Code ausgelöst wird, eventHandler aufgerufen, der das Ergebnis in die Konsolenprotokollierung schreibt.