Native Module je třída Java nebo Objective-C, která zpřístupňuje nativní API platformy z JavaScriptu v React Native. Každý modul se registruje v Bridge a exportuje metody, které lze volat z JS kódu jako běžné funkce. Podle údajů Meta, 2024 zůstává Native Module hlavním způsobem integrace platformního kódu v aplikacích React Native.
Hlavní body
Native Module je architektonický prvek React Native, který umožňuje spouštět kód v jazyce platformy (Objective-C/Swift pro iOS, Java/Kotlin pro Android) a vracet výsledek do JavaScriptu. Bez Native Module není možný přístup k nativním schopnostem zařízení — kameře, GPS, akcelerometru, souborovému systému nebo Bluetooth.
React Native je dodáván se sadou vestavěných Native Module: CameraRoll, AsyncStorage, Geolocation, NetInfo a další. Pro specifické úkoly — integrace SDK třetích stran, práce s hardwarovými senzory nebo procesy na pozadí — si však vývojář vytváří vlastní moduly. Podle průzkumu State of React Native 2024 používá 67 % vývojářů alespoň jeden vlastní Native Module ve svých projektech.
Architektura Native Module závisí na verzi React Native. V klasické architektuře (React Native 0.72 a starší) se modul připojuje přes Bridge a komunikuje s JS asynchronně přes JSON serializaci. V nové architektuře (React Native 0.76+) může modul fungovat jako Turbo Module s využitím JSI pro synchronní přístup bez serializace.
Vytvoření Native Module pro iOS začíná deklarací třídy Objective-C, která implementuje protokol RCTBridgeModule. Makro RCT_EXPORT_MODULE registruje modul v Bridge a RCT_EXPORT_METHOD exportuje metodu přístupnou z JavaScriptu.
// ImageCompressor.m — Native Module pro 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
Metoda compressImage přijímá cestu k obrázku a kvalitu komprese (0.0–1.0), zpracovává data na nativní straně a vrací cestu ke komprimovanému souboru. Klíčová výhoda — komprese se provádí nativním kódem, což je výrazně rychlejší a paměťově efektivnější než obdobná operace v JavaScriptu.
Pro moduly Swift se používá anotace @objc před třídou a metodami, aby byly přístupné runtime Objective-C, se kterým Bridge pracuje. Třída musí dědit z NSObject a implementovat RCTBridgeModule.
// 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)
}
}
Na Androidu se Native Module vytváří jako třída Java dědící z ReactContextBaseJavaModule. Anotace @ReactMethod exportuje metodu do Bridge. Pro vrácení výsledku se používá rozhraní Promise z com.facebook.react.bridge.
// 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());
}
}
}
Metoda getName() vrací název modulu, pod kterým bude přístupný z JavaScriptu. V uvedeném příkladu se modul registruje jako ImageCompressor. Anotace @ReactMethod indikuje Bridge, že metoda má být exportována. Důležité: metody musí být void a přijímat pouze typy podporované Bridge: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.
Po vytvoření třídy je nutné modul zaregistrovat v balíčku aplikace. K tomu se vytvoří třída implementující ReactPackage a přidá se do seznamu modulů v metodě createNativeModules.
// ImageCompressorPackage.java — registrace modulu
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();
}
}
Po vytvoření modulů pro obě platformy je třeba je zaregistrovat v React Native. Pro Android se balíček přidá do MainApplication.java v metodě getPackages(). Pro iOS se modul registruje automaticky přes makro RCT_EXPORT_MODULE, ale lze použít i ruční registraci v souboru AppDelegate.mm.
// MainApplication.java — přidání balíčku do React Native
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;
}
};
}
Po registraci je modul přístupný v JavaScriptu přes NativeModules. React Native automaticky dosadí název modulu uvedený v getName() pro Android nebo v RCT_EXPORT_MODULE pro iOS.
// Použití Native Module z JavaScriptu
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('Komprimováno:', result);
return result;
} catch (error) {
console.error('Komprese selhala:', error);
throw error;
}
}
Srovnání klasického Native Module a Turbo Module pomáhá pochopit, který přístup zvolit pro nový projekt. Oba mechanismy poskytují přístup k nativnímu kódu, ale zásadně se liší architekturou a výkonem.
| Vlastnost | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| Komunikace | Asynchronní přes JSON | Synchronní přes JSI |
| Serializace | JSON při každém volání | Bez kopírování dat |
| Typování | Ruční, bez generování | Automatické přes Codegen |
| Načítání | Při inicializaci aplikace | Líné (lazy load) |
| Kompatibilita | Všechny verze React Native | React Native 0.73+ |
Pro existující projekty na React Native 0.72 a starších zůstává klasický Native Module hlavní volbou. Pro nové projekty se doporučuje používat Turbo Module, zejména pokud je vyžadován vysoký výkon při častém volání nativních metod. S postupnou aktualizací React Native se komunita pohybuje směrem k úplnému přechodu na novou architekturu.
Často kladené otázky
Ano, Bridge podporuje callback. Místo Promise lze použít funkce zpětného volání RCTResponseSenderBlock v iOS a Callback v Androidu. Promise je však považován za moderní standard a je doporučován pro nové moduly.
Native Module se ladí jako běžný nativní kód — nastavte breakpointy v Xcode nebo Android Studio. Pro iOS použijte schéma sestavení s React Native, pro Android — konfiguraci Debug. Vstupní bod — metody volané z JS.
Native Module přes Bridge nepodporuje binární data (NSData/byte[]), vlastní objekty a funkce. Pro přenos obrázků použijte cestu k souboru nebo base64 řetězec. Turbo Module přes JSI odstraňuje část těchto omezení.
Obvykle ne — Native Module API je stabilní a zpětně kompatibilní. Při přechodu na novou architekturu (Turbo Module) se modul adaptuje pomocí dekorátorů, ale stávající kód nadále funguje.
Použijte RCTEventEmitter v iOS nebo DeviceEventEmitter v Androidu. Modul odešle událost a JS strana se přihlásí k odběru přes NativeEventEmitter z react-native. To je užitečné pro streamovaná data a události senzorů.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také