A Native Module egy Java vagy Objective-C osztály, amely a platform natív API-it elérhetővé teszi a JavaScript számára a React Native-ban. Minden modul regisztrálásra kerül a Bridge-ben és olyan metódusokat exportál, amelyek a JS-kódból hétköznapi függvényekként hívhatók meg. A Meta, 2024 adatai szerint a Native Module továbbra is a platformkód integrálásának elsődleges módja a React Native alkalmazásokban.
Főbb pontok
Native Module a React Native egy architekturális eleme, amely lehetővé teszi a kód futtatását a platform nyelvén (Objective-C/Swift iOS-hez, Java/Kotlin Android-hoz) és az eredmény visszaküldését a JavaScript-be. Native Module nélkül lehetetlen hozzáférni az eszköz natív képességeihez — kamerához, GPS-hez, gyorsulásmérőhöz, fájlrendszerhez vagy Bluetooth-hoz.
A React Native beépített Native Module-ok készletével érkezik: CameraRoll, AsyncStorage, Geolocation, NetInfo és mások. Azonban specifikus feladatokhoz — harmadik féltől származó SDK integrálása, hardverérzékelőkkel való munka vagy háttérfolyamatok — a fejlesztő saját modulokat hoz létre. A State of React Native 2024 felmérés szerint a fejlesztők 67%-a használ legalább egy egyedi Native Module-t a projektjeiben.
A Native Module architektúrája a React Native verziójától függ. A klasszikus architektúrában (React Native 0.72 és régebbi) a modul a Bridge-en keresztül csatlakozik és aszinkron módon kommunikál a JS-sel JSON szerializáción keresztül. Az új architektúrában (React Native 0.76+) a modul Turbo Module-ként működhet, a JSI-t használva szinkron hozzáféréshez szerializáció nélkül.
Native Module létrehozása iOS-hez egy Objective-C osztály deklarálásával kezdődik, amely implementálja az RCTBridgeModule protokollt. Az RCT_EXPORT_MODULE makró regisztrálja a modult a Bridge-ben, az RCT_EXPORT_METHOD pedig exportál egy JavaScript-ből elérhető metódust.
// ImageCompressor.m — Native Module iOS-hez
@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
A compressImage metódus fogadja a kép elérési útját és a tömörítés minőségét (0.0–1.0), feldolgozza az adatokat a natív oldalon és visszaadja a tömörített fájl elérési útját. A kulcsfontosságú előny — a tömörítés natív kóddal történik, ami jelentősen gyorsabb és memóriahatékonyabb, mint egy hasonló művelet JavaScript-ben.
A Swift modulok esetében az @objc annotációt használjuk az osztály és metódusok előtt, hogy elérhetőek legyenek az Objective-C futási környezet számára, amellyel a Bridge dolgozik. Az osztálynak az NSObject-ből kell örökölnie és implementálnia kell az RCTBridgeModule-t.
// 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)
}
}
Androidon a Native Module egy Java osztályként jön létre, amely a ReactContextBaseJavaModule-ből örököl. Az @ReactMethod annotáció exportálja a metódust a Bridge-be. Az eredmény visszaküldéséhez a com.facebook.react.bridge csomag Promise interfészét használjuk.
// 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());
}
}
}
A getName() metódus visszaadja a modul nevét, amely alatt JavaScript-ből elérhető lesz. A megadott példában a modul ImageCompressor néven regisztrálódik. Az @ReactMethod annotáció jelzi a Bridge-nek, hogy a metódust exportálni kell. Fontos: a metódusoknak void-nak kell lenniük és csak a Bridge által támogatott típusokat fogadhatják: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.
Az osztály létrehozása után a modult regisztrálni kell az alkalmazáscsomagban. Ehhez létrejön egy osztály, amely implementálja a ReactPackage-et és hozzáadódik a modulok listájához a createNativeModules metódusban.
// ImageCompressorPackage.java — modul regisztráció
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();
}
}
A modulok létrehozása után mindkét platformon regisztrálni kell őket a React Native-ban. Android esetén a csomag hozzáadódik a MainApplication.java fájlban a getPackages() metódusban. iOS esetén a modul automatikusan regisztrálódik az RCT_EXPORT_MODULE makrón keresztül, de használható manuális regisztráció is az AppDelegate.mm fájlban.
// MainApplication.java — csomag hozzáadása a React Native-hoz
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;
}
};
}
Regisztráció után a modul elérhetővé válik JavaScript-ben a NativeModules-on keresztül. A React Native automatikusan behelyettesíti a getName()-ben (Android) vagy az RCT_EXPORT_MODULE-ben (iOS) megadott modulnevet.
// Native Module használata JavaScript-ből
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('Tömörítve:', result);
return result;
} catch (error) {
console.error('Tömörítés sikertelen:', error);
throw error;
}
}
A klasszikus Native Module és a Turbo Module összehasonlítása segít megérteni, hogy melyik megközelítést válasszuk egy új projekthez. Mindkét mechanizmus hozzáférést biztosít a natív kódhoz, de alapvetően különböznek architektúrában és teljesítményben.
| Jellemző | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| Kommunikáció | Aszinkron JSON-on keresztül | Szinkron JSI-n keresztül |
| Szerializáció | JSON minden híváskor | Adatmásolás nélkül |
| Típizálás | Kézi, generálás nélkül | Automatikus Codegen-en keresztül |
| Betöltés | Az alkalmazás inicializálásakor | Lusta (lazy load) |
| Kompatibilitás | Minden React Native verzió | React Native 0.73+ |
A meglévő, React Native 0.72 és régebbi verziójú projektek esetében a klasszikus Native Module marad az elsődleges választás. Új projektekhez a Turbo Module használata ajánlott, különösen ha gyakori natív metódushívásoknál magas teljesítményre van szükség. A React Native fokozatos frissítésével a közösség a teljes átállás felé halad az új architektúrára.
Gyakran ismételt kérdések
Igen, a Bridge támogatja a callback-et. Promise helyett használhatók az RCTResponseSenderBlock visszahívási függvények iOS-ben és a Callback Android-ban. Azonban a Promise modern szabványnak számít és új modulokhoz ajánlott.
A Native Module hibakeresése hétköznapi natív kódként történik — állítson be töréspontokat Xcode-ban vagy Android Studio-ban. iOS-hez használja a React Native-val való build sémát, Android-hoz — Debug konfigurációt. A belépési pont — a JS-ből hívott metódusok.
Native Module a Bridge-en keresztül nem támogat bináris adatokat (NSData/byte[]), egyedi objektumokat és függvényeket. Képek küldéséhez használjon fájl elérési utat vagy base64 karakterláncot. A Turbo Module a JSI-n keresztül e korlátozások egy részét megszünteti.
Általában nem — a Native Module API stabil és visszafelé kompatibilis. Az új architektúrára (Turbo Module) való áttéréskor a modul dekorátorokkal adaptálható, de a meglévő kód tovább működik.
Használja az RCTEventEmitter-t iOS-ben vagy a DeviceEventEmitter-t Android-ban. A modul elküldi az eseményt, a JS oldal pedig feliratkozik a react-native NativeEventEmitter-jén keresztül. Ez hasznos adatfolyamokhoz és érzékelő eseményekhez.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is