Native Module ist eine Java- oder Objective-C-Klasse, die native Plattform-APIs aus JavaScript in React Native zugänglich macht. Jedes Modul wird im Bridge registriert und exportiert Methoden, die aus JS-Code wie normale Funktionen aufgerufen werden können. Laut Meta, 2024 bleibt Native Module der primäre Weg, um Plattformcode in React Native-Anwendungen zu integrieren.
Wichtige Punkte
Native Module ist ein architektonisches Element von React Native, das die Ausführung von Code in der Plattformsprache (Objective-C/Swift für iOS, Java/Kotlin für Android) und die Rückgabe des Ergebnisses an JavaScript ermöglicht. Ohne ein Native Module ist es unmöglich, auf native Gerätefunktionen zuzugreifen — Kamera, GPS, Beschleunigungsmesser, Dateisystem oder Bluetooth.
React Native wird mit einer Reihe integrierter Native Module ausgeliefert: CameraRoll, AsyncStorage, Geolocation, NetInfo und andere. Für spezifische Aufgaben — Integration von Drittanbieter-SDKs, Arbeit mit Hardware-Sensoren oder Hintergrundprozesse — erstellt der Entwickler jedoch benutzerdefinierte Module. Laut der State of React Native 2024 Umfrage verwenden 67% der Entwickler mindestens ein benutzerdefiniertes Native Module in ihren Projekten.
Die Architektur des Native Module hängt von der React Native Version ab. In der klassischen Architektur (React Native 0.72 und älter) verbindet sich das Modul über den Bridge und kommuniziert asynchron mit JS über JSON-Serialisierung. In der neuen Architektur (React Native 0.76+) kann das Modul als Turbo Module arbeiten und JSI für synchronen Zugriff ohne Serialisierung verwenden.
Die Erstellung eines Native Module für iOS beginnt mit der Deklaration einer Objective-C-Klasse, die das RCTBridgeModule-Protokoll implementiert. Das Makro RCT_EXPORT_MODULE registriert das Modul im Bridge, und RCT_EXPORT_METHOD exportiert eine Methode, die aus JavaScript verfügbar ist.
// ImageCompressor.m — Native Module für iOS
@interface ImageCompressor () RCT_EXPORT_MODULE()
@end
@implementation ImageCompressor
RCT_EXPORT_METHOD(compressImage:(NSString *)imagePath
quality:(NSNumber *)quality
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
NSData *compressedData = [UIImageJPEGRepresentation(image, quality.floatValue)];
NSString *outputPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"compressed.jpg"];
[compressedData writeToFile:outputPath atomically:YES];
resolve(outputPath);
}
@end
Die Methode compressImage nimmt einen Bildpfad und eine Komprimierungsqualität (0.0–1.0) entgegen, verarbeitet die Daten auf der nativen Seite und gibt den Pfad zur komprimierten Datei zurück. Der Hauptvorteil ist, dass die Komprimierung durch nativen Code erfolgt, was deutlich schneller und speichereffizienter ist als die äquivalente JavaScript-Operation.
Für Swift-Module wird die @objc-Annotation vor der Klasse und den Methoden verwendet, um sie für die Objective-C-Laufzeitumgebung verfügbar zu machen, mit der der Bridge arbeitet. Die Klasse muss von NSObject erben und RCTBridgeModule implementieren.
// ImageCompressor.swift — Swift Native Module
@objc(ImageCompressor)
class ImageCompressor: NSObject {
@objc
func compressImage(
_ imagePath: String,
quality: Float,
resolver: @escaping RCTPromiseResolveBlock,
rejecter: @escaping RCTPromiseRejectBlock
) {
guard let image = UIImage(contentsOfFile: imagePath) else {
rejecter("FILE_ERROR", "Cannot load image", nil)
return
}
guard let data = image.jpegData(compressionQuality: CGFloat(quality)) else {
rejecter("COMPRESS_ERROR", "Compression failed", nil)
return
}
let outputPath = NSTemporaryDirectory() + "compressed.jpg"
try? data.write(to: URL(fileURLWithPath: outputPath))
resolver(outputPath)
}
}
Unter Android wird ein Native Module als Java-Klasse erstellt, die ReactContextBaseJavaModule erweitert. Die @ReactMethod-Annotation exportiert die Methode in den Bridge. Die Promise-Schnittstelle aus com.facebook.react.bridge wird verwendet, um Ergebnisse zurückzugeben.
// ImageCompressorModule.java — Android Native Module
public class ImageCompressorModule
extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "ImageCompressor";
}
@ReactMethod
public void compressImage(
String imagePath,
Float quality,
Promise promise) {
try {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
File outputFile = new File(
ReactNative.getApplicationContext()
.getCacheDir(), "compressed.jpg");
FileOutputStream fos = new FileOutputStream(outputFile);
bitmap.compress(
Bitmap.CompressFormat.JPEG,
(int)(quality * 100), fos);
fos.close();
promise.resolve(outputFile.getAbsolutePath());
} catch (Exception e) {
promise.reject("COMPRESS_ERROR", e.getMessage());
}
}
}
Die Methode getName() gibt den Modulnamen zurück, unter dem es aus JavaScript zugänglich sein wird. Im obigen Beispiel wird das Modul als ImageCompressor registriert. Die @ReactMethod-Annotation teilt dem Bridge mit, dass die Methode exportiert werden soll. Wichtig: Methoden müssen void sein und nur vom Bridge unterstützte Typen akzeptieren: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.
Nach dem Erstellen der Modulklasse muss sie im Anwendungspaket registriert werden. Dazu wird eine Klasse erstellt, die ReactPackage implementiert, und in der Methode createNativeModules zur Modulliste hinzugefügt.
// ImageCompressorPackage.java — Modulregistrierung
public class ImageCompressorPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
return Arrays.asList(
new ImageCompressorModule(reactContext)
);
}
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Nachdem die Module für beide Plattformen erstellt wurden, müssen sie in React Native registriert werden. Für Android wird das Paket in MainApplication.java in der Methode getPackages() hinzugefügt. Für iOS wird das Modul automatisch über das Makro RCT_EXPORT_MODULE registriert, aber eine manuelle Registrierung in AppDelegate.mm kann ebenfalls verwendet werden.
// MainApplication.java — Paket zu React Native hinzufügen
import com.yourapp.nativemodules.ImageCompressorPackage;
public class MainApplication extends Application
implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages =
new PackageList(this).getPackages();
packages.add(new ImageCompressorPackage());
return packages;
}
};
}
Nach der Registrierung ist das Modul in JavaScript über NativeModules verfügbar. React Native verwendet automatisch den in getName() für Android oder RCT_EXPORT_MODULE für iOS angegebenen Modulnamen.
// Native Module aus JavaScript verwenden
import { NativeModules } from 'react-native';
import { Platform } from 'react-native';
const ImageCompressor = NativeModules.ImageCompressor;
async function compressPhoto(uri: string) {
try {
const result = await ImageCompressor.compressImage(
uri.replace('file://', ''), 0.8
);
console.log('Komprimiert:', result);
return result;
} catch (error) {
console.error('Komprimierung fehlgeschlagen:', error);
throw error;
}
}
Der Vergleich des klassischen Native Module mit Turbo Module hilft zu verstehen, welcher Ansatz für ein neues Projekt zu wählen ist. Beide Mechanismen bieten Zugriff auf nativen Code, unterscheiden sich jedoch grundlegend in Architektur und Leistung.
| Eigenschaft | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| Kommunikation | Asynchron über JSON | Synchron über JSI |
| Serialisierung | JSON bei jedem Aufruf | Ohne Datenkopie |
| Typisierung | Manuell, ohne Generierung | Automatisch über Codegen |
| Laden | Bei Anwendungsinitialisierung | Lazy Load |
| Kompatibilität | Alle React Native Versionen | React Native 0.73+ |
Für bestehende Projekte auf React Native 0.72 und älter bleiben klassische Native Modules die erste Wahl. Für neue Projekte wird Turbo Module empfohlen, insbesondere wenn bei häufigen nativen Methodenaufrufen eine hohe Leistung erforderlich ist. Mit der schrittweisen Aktualisierung von React Native bewegt sich die Community in Richtung eines vollständigen Übergangs zur neuen Architektur.
Häufig gestellte Fragen
Ja, der Bridge unterstützt Callbacks. Anstelle von Promise können RCTResponseSenderBlock-Callback-Funktionen in iOS und Callback in Android verwendet werden. Promise gilt jedoch als moderner Standard und wird für neue Module empfohlen.
Ein Native Module wird wie gewöhnlicher nativer Code debuggt — setzen Sie Haltepunkte in Xcode oder Android Studio. Für iOS verwenden Sie das Build-Schema mit React Native, für Android die Debug-Konfiguration. Der Einstiegspunkt sind die aus JS aufgerufenen Methoden.
Native Module über den Bridge unterstützt keine binären Daten (NSData/byte[]), benutzerdefinierte Objekte und Funktionen. Für Bilder verwenden Sie einen Dateipfad oder einen base64-String. Turbo Module über JSI hebt einige dieser Einschränkungen auf.
In der Regel nein — die Native Module API ist stabil und abwärtskompatibel. Beim Übergang zur neuen Architektur (Turbo Module) wird das Modul durch Dekorateure angepasst, aber der vorhandene Code funktioniert weiterhin.
Verwenden Sie RCTEventEmitter in iOS oder DeviceEventEmitter in Android. Das Modul sendet ein Ereignis, und die JS-Seite abonniert über NativeEventEmitter von react-native. Dies ist nützlich für Streaming-Daten und Sensorereignisse.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch