Table of Contents
Einführung in Native Module in React Native
React Native ermöglicht es Entwicklern, plattformübergreifende mobile Anwendungen mit JavaScript und React zu erstellen. Während das Framework mit einem umfangreichen Satz integrierter Komponenten für gängige UI-Elemente und Core-Geräte-APIs ausgestattet ist, erfordern Produktions-Apps oft Funktionen, die über die Standard-Javascript-Laufzeit von React Native hinausgehen. Native Module dienen als Brücke zwischen JavaScript und plattformspezifischem Code, der in Swift, Objective‐C, Kotlin oder Java geschrieben ist. Sie ermöglichen den Zugriff auf Hardware-Sensoren, Systemdienste, SDKs von Drittanbietern und leistungssensitive Funktionen, die sonst mit reinem JavaScript schwer oder unmöglich zu implementieren wären.
In diesem Handbuch werden wir den gesamten Lebenszyklus eines nativen Moduls durchgehen – vom Einrichten Ihrer Umgebung und dem Schreiben von Plattformcode über die Registrierung des Moduls, das Aussetzen von Methoden und deren Verbrauch aus JavaScript. Wir werden auch Best Practices, Leistungsüberlegungen und reale Beispiele wie den Zugriff auf die Kamera, die Bearbeitung von Hintergrundaufgaben und die Kommunikation zwischen Threads behandeln. Am Ende haben Sie eine solide Grundlage, um die Fähigkeiten von React Native mit Ihren eigenen nativen Modulen zu erweitern.
Native Module und die Brücke verstehen
Im Kern basiert die Architektur von React Native auf einer Bridge, die Nachrichten zwischen dem JavaScript-Thread und den nativen Threads serialisiert und deserialisiert. Native Module sind Objekte, die auf der nativen Seite leben und mit der JavaScript-Laufzeit registriert sind. Wenn Sie eine Methode von JS aus aufrufen, sendet die Bridge eine Nachricht an die native Seite, führt die Methode aus und gibt das Ergebnis (falls vorhanden) zurück an JS. Dieses Muster ermöglicht es Ihnen, System-APIs zu nutzen - zum Beispiel Zugriff auf das Gyroskop des Geräts, Lesen von NFC-Tags oder Verschlüsselung von Daten mit der sicheren Enklave der Plattform -, die nicht durch die Standardbibliotheken von React Native freigelegt werden.
Native Module sind besonders in den folgenden Szenarien wertvoll:
- Sie müssen eine native Bibliothek (z. B. für die Zahlungsverarbeitung, maschinelles Lernen oder Augmented Reality) integrieren, die keinen JavaScript-Wrapper hat.
- Sie benötigen leistungsstarke, latenzarme Operationen, die durch den JS-Thread verlangsamt werden würden (z. B. Bildverarbeitung, Audiosynthese).
- Sie müssen auf plattformspezifische Funktionen zugreifen, die nicht Teil des Kerns von React Native sind - wie das iOS HomeKit oder die biometrische Eingabeaufforderung von Android.
- Sie möchten Code zwischen einer React Native App und einer vorhandenen nativen Codebasis teilen.
Bevor wir in die Implementierung einsteigen, ist es wichtig zu verstehen, dass native Module keine "magische Kugel" sind - sie erhöhen die Komplexität, erfordern Tests auf jeder Plattform und können Sicherheitsbedenken mit sich bringen.
Einrichtung Ihrer Entwicklungsumgebung
Um native Module zu erstellen, benötigen Sie die Standard-Entwicklungsumgebung React Native für Android und iOS. Dazu gehören Java/Kotlin-Tools für Android (Android Studio, Gradle, das Android SDK) und Xcode für iOS mit CocoaPods (oder Swift Package Manager) für das Abhängigkeitsmanagement. Stellen Sie sicher, dass Sie React Native-Code geschrieben haben, bevor Sie native Module ausprobieren - Sie sollten sich mit den Grundlagen der Erstellung eines React Native-Projekts und dem Verständnis der Dateistruktur vertraut machen.
Die meisten Entwickler beginnen mit einem React Native Projekt, das über erstellt wurde. Innerhalb des Projekts werden native Module in der Regel innerhalb der und Verzeichnisse platziert. Aus Gründen der Modularität und Wiederverwendbarkeit können Sie Ihr natives Modul auch als separates npm-Paket umhüllen – viele Community-Module folgen diesem Muster. Wir werden uns auf den In-Projekt-Ansatz konzentrieren, um Klarheit zu schaffen.
Erstellen eines nativen Moduls: Die Grundlagen
Jedes native Modul besteht aus zwei Teilen: der plattformspezifischen Implementierung (einer für Android, einer für iOS) und dem JavaScript-Verbrauchscode.
Android (Kotlin/Java)
Unter Android erstellen Sie eine Klasse, die erweitert und die Methoden implementiert, die Sie freilegen möchten. Jede Methode, die aus JavaScript aufgerufen werden soll, muss mit annotiert sein und einen Rückgabetyp haben (oder einen Rückruf / Versprechen verwenden, um Daten zurückzugeben).
package com.yourapp
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
class MyNativeModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName(): String = "MyNativeModule"
@ReactMethod
fun doSomething(param: String, promise: Promise) {
try {
// Perform native work here
val result = "Hello from Kotlin! Received: $param"
promise.resolve(result)
} catch (e: Exception) {
promise.reject("ERROR", e.message)
}
}
}
Nachdem Sie das Modul definiert haben, müssen Sie es mit dem Paketsystem von React Native registrieren.
package com.yourapp
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager
class MyNativePackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(MyNativeModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
Fügen Sie das Paket schließlich zu Ihrem (oder ) innerhalb der -Methode hinzu:
override fun getPackages(): List<ReactPackage> {
val packages = PackageList(this).packages
packages.add(MyNativePackage())
return packages
}
iOS (Swift/Objective-C)
Unter iOS werden native Module normalerweise in Objective-C oder Swift geschrieben. React Native erwartet eine Header-Datei und Implementierung, die dem -Protokoll entspricht. Für Swift müssen Sie einen Brückenkopf erstellen. Hier ist ein Objective-C-Beispiel:
// MyNativeModule.h
#import <React/RCTBridgeModule.h>
@interface MyNativeModule : NSObject <RCTBridgeModule>
@end
// MyNativeModule.m
#import "MyNativeModule.h"
#import <React/RCTLog.h>
@implementation MyNativeModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(doSomething:(NSString *)param
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSString *result = [NSString stringWithFormat:@"Hello from iOS! Received: %@", param];
resolve(result);
}
@end
Für iOS ist keine zusätzliche Paketregistrierung erforderlich – React Native erkennt automatisch Klassen, die entsprechen. Allerdings müssen Sie sicherstellen, dass die .m-Datei in Ihrem Ziel kompiliert ist und dass Sie ausführen, wenn Sie native Abhängigkeiten hinzufügen.
Für Swift sind die Schritte ähnlich, erfordern aber das -Attribut und einen Brückenkopf.
import Foundation
@objc(MyNativeModule)
class MyNativeModule: NSObject {
@objc
func doSomething(_ param: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
let result = "Hello from Swift! Received: \(param)"
resolve(result)
}
}
Denke daran, in deinen Objective-C-Bridge-Header zu importieren: .
Native Module aus JavaScript verwenden
Sobald Ihr natives Modul implementiert und registriert ist, können Sie über das -Objekt auf dieses in Ihrem React Native JavaScript-Code zugreifen. Der Name, den Sie in (Android) oder (iOS) angeben, wird zum Schlüssel, unter dem das Modul erscheint.
import { NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;
// Calling an exported method
MyNativeModule.doSomething('React Native')
.then(result => console.log(result))
.catch(error => console.error(error));
Sie können auch oder Event-Handler nach Bedarf verwenden. Beachten Sie, dass der Methodenname in JavaScript genau mit dem Methodennamen übereinstimmen muss, den Sie im nativen Code exportiert haben. React Native ordnet sie 1:1 zu und ignoriert den Namensparameter der Android-Methodenannotation, wenn Sie ihn außer Kraft setzen.
Für Methoden, die mehrere Parameter akzeptieren, geben Sie sie einfach als Argumente weiter – die Brücke wird die Serialisierung handhaben. Unterstützte Parametertypen umfassen , , , , (Maps) und Funktionen (Callbacks). Die Verwendung von Promises über das -Argument (Android) oder die Resolver/Rejecter-Blöcke (iOS) ist jedoch der empfohlene Ansatz, da sie sich sauber in die asynchrone Natur von React Native integrieren lässt.
Fortgeschrittene Kommunikationsmuster
Während grundlegende Methodenaufrufe viele Anwendungsfälle abdecken, erfordern erweiterte Funktionen oft ausgefeiltere Kommunikationsmuster. React Native unterstützt mehrere Mechanismen:
Callbacks vs. Versprechen
Für einmalige Operationen sind Promises am saubersten. Für kontinuierliche Datenströme (z. B. Sensormessungen) bevorzugen Sie möglicherweise Rückrufe. Rückrufe sind jedoch in modernen React Native weniger verbreitet, da sie zu Rückruf-Hölle führen können. Ein besseres Muster für Streams ist es, Ereignisse von der nativen Seite über (iOS) oder und (Android) nach JavaScript zu emittieren.
Emittieren von Ereignissen von Native zu JavaScript
Um Daten asynchron vom nativen Code an JS zu senden (z. B. wenn ein nativer Sensor aktualisiert wird), können Sie den Ereignisemitter Singleton verwenden.
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit("onSensorUpdate", Arguments.createMap().apply {
putString("data", sensorValue)
})
Importieren Sie unter iOS und überschreiben Sie unterstützte Ereignisse:
@implementation MyNativeModule
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents {
return @[@"onSensorUpdate"];
}
// In your native method or delegate callback:
[self sendEventWithName:@"onSensorUpdate" body:@{@"data": sensorValue}];
@end
In JavaScript abonnieren Sie das Ereignis mit :
import { NativeEventEmitter, NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;
const eventEmitter = new NativeEventEmitter(MyNativeModule);
eventEmitter.addListener('onSensorUpdate', (event) => {
console.log('Sensor data:', event.data);
});
Vergessen Sie nicht, die Zuhörer zu entfernen, wenn sich die Komponente aus dem Speicher löst, um Speicherverluste zu vermeiden.
Thread Management und Performance
Standardmäßig laufen alle nativen Modulmethodeaufrufe im nativen Threadpool, getrennt vom UI-Thread. Dies ist für die meisten Operationen in Ordnung, aber wenn Sie die Benutzeroberfläche direkt von Ihrem nativen Modul aktualisieren müssen (z. B. eine umfangreiche Berechnung durchführen und eine Ansicht aktualisieren), müssen Sie die Arbeit an den Hauptthread senden. Verwenden Sie auf Android ; Verwenden Sie auf iOS .
Für lang laufende Hintergrundaufgaben (wie Datenbanksynchronisation oder Bluetooth-Scanning) sollten Sie oder Rückrufe in Betracht ziehen, um eine Blockierung der Brücke zu vermeiden. Sie können auch zusätzliche Threads in Ihrem nativen Modul erzeugen, aber seien Sie vorsichtig mit der Threadsicherheit - der gemeinsame Zustand muss synchronisiert werden.
Leistungstipp: Minimierung der Datengröße, die durch die Brücke geleitet werden. Große Arrays oder binäre Blobs (z. B. Bilder) sollten mit Dateipfaden oder Referenzen behandelt werden, anstatt in JSON serialisiert zu werden.
Beispiele aus der realen Welt
Um die Konzepte zu verfestigen, betrachten wir zwei gängige Anwendungsfälle, in denen native Module unverzichtbar sind.
Kamerazugang
React Native hat eine eingebaute , enthält aber keine Low-Level-Kamera-API. Ein natives Modul kann die Kamera der Plattform umwickeln - zum Beispiel die -API von Android oder die von iOS. Ihr Modul könnte Methoden zum Öffnen der Kameravorschau, zum Aufnehmen eines Fotos und zum Zurückgeben des Bildpfads an JS aussetzen. Genau das tun gängige Bibliotheken wie . Durch das Schreiben Ihrer eigenen haben Sie die volle Kontrolle über die Bildverarbeitung, die Flash-Einstellungen und den manuellen Fokus.
Bluetooth Low Energy (BLE) Kommunikation
Die Verbindung mit BLE-Peripheriegeräten (z. B. Herzfrequenzmonitoren, Beacons) erfordert native System-APIs. Ein natives Modul kann nach Geräten suchen, sich verbinden, Dienste entdecken und Lese-/Schreibeigenschaften lesen. Da BLE-Operationen asynchron sind und oft Rückrufe beinhalten, ist das Aussenden von Ereignissen (wie oder das natürliche Muster. Es gibt mehrere Open-Source-BLE-Module, aber das Erstellen eigener Module stellt sicher, dass Sie nur die Funktionalität Ihrer App bereitstellen und Ihnen die Kontrolle über das Threading geben.
Best Practices und Fallstricke
- Schreibgerätetests auf nativen Code. Sowohl Android Studio als auch Xcode bieten Test-Frameworks (JUnit, XCTest).
- Berechtigungen können anmutig gehandhabt werden. Viele Native-Module benötigen Laufzeitberechtigungen (Kamera, Standort, Bluetooth). React Native’s funktioniert für Android, aber für iOS müssen Sie möglicherweise Berechtigungen aus Ihrem nativen Modul anfordern oder eine Bibliothek wie verwenden.
- Halten Sie die Brücke Licht. Vermeiden Sie es, häufig große Objekte zu passieren. Wenn Sie Hochfrequenzdaten streamen müssen (z. B. Sensor bei 100 Hz), sollten Sie Batch-Updates in Betracht ziehen oder zu einem Modell wechseln, bei dem nativer Code Daten vorverarbeitet und nur aggregierte Ergebnisse sendet.
- Dokumentieren Sie die API Ihres nativen Moduls gründlich. Verwenden Sie JSDoc oder eine README, um jede Methode, ihre Parameter, Rückgabewerte und Plattformunterschiede zu beschreiben. Dies ist entscheidend, wenn andere Teammitglieder oder die Open-Source-Community Ihr Modul nutzen.
- Nutzung erst nach der Initialisierung der App. Da native Module darauf angewiesen sind, dass die Bridge bereit ist, kann der Zugriff auf sie zu früh (z. B. in einem globalen Kontext) zu führen.
- Nutze bestehende Module, wenn möglich. Das React Native Ökosystem hat Tausende von Paketen. Bevor du dein eigenes natives Modul schreibst, suche nach vorhandenen. Wenn du ein Modul findest, das fast deinen Bedürfnissen entspricht, dann ziehe es in Betracht, etwas beizutragen, anstatt das Rad neu zu erfinden.
- Betrachten Sie TurboModule für neue Projekte. Ausgehend von React Native 0.68 bietet die neue Architektur mit TurboModules eine bessere Leistung und JavaScript-native Memory-Sharing. Wenn Sie eine neue App starten, verwenden Sie TurboModules (über die Neue Architektur) anstelle der alten Brücke.
Externe Ressourcen
Um tiefer in die Entwicklung nativer Module einzutauchen, konsultieren Sie die offizielle React Native Dokumentation zu nativen Modulen. Für plattformspezifische Anleitungen bieten die Android Developer Guides und Apples Entwicklerdokumentation maßgebliche Referenzen. Darüber hinaus beherbergt die Community-unterstützte React Native Community GitHub Organisation viele gut getestete native Module, die Sie als Beispiele studieren können.
Schlussfolgerung
Native Module sind ein mächtiges Werkzeug im Arsenal der React Native Entwickler, das den Zugriff auf die gesamte Bandbreite der Plattformfähigkeiten ermöglicht. Während sie zusätzliche Komplexität einführen - Wissen über Java / Kotlin oder Swift / Objective-C, sorgfältiges Thread-Management und strenge Tests erfordern - ist die Auszahlung die Fähigkeit, erweiterte Funktionen zu liefern, die sonst unmöglich wären. Durch die Einhaltung der in diesem Handbuch beschriebenen Muster - Erstellen eines gut strukturierten nativen Moduls, Verwenden von Versprechen und Ereignissen für saubere async Kommunikation und Einhaltung von Best Practices um Berechtigungen und Leistung - können Sie React Native sicher über seine eingebauten Grenzen hinaus erweitern.
Fangen Sie klein an: bauen Sie ein einfaches Rechenmodul, das zwei Zahlen multipliziert und das Ergebnis zurückgibt. Dann gehen Sie zu komplexeren Modulen wie einer Batteriefüllstandsanzeige oder einem benutzerdefinierten Bildfilter. Jedes native Modul, das Sie erstellen, vertieft Ihr Verständnis der Plattform und macht Sie zu einem vielseitigeren mobilen Entwickler.