Native Module — React Native-də JavaScript-dən platformanın nativ API-lərini əlçatan edən Java və ya Objective-C sinifidir. Hər modul Bridge-də qeydiyyatdan keçir və JS kodundan adi funksiyalar kimi çağırıla bilən metodları ixrac edir. Meta, 2024 məlumatlarına görə, Native Module React Native tətbiqlərində platforma kodunun inteqrasiyasının əsas yolu olaraq qalır.
Əsas məqamlar
Native Module — React Native-in arxitektura elementidir, platforma dilində (iOS üçün Objective-C/Swift, Android üçün Java/Kotlin) kod icra etməyə və nəticəni JavaScript-ə qaytarmağa imkan verir. Native Module olmadan cihazın nativ imkanlarına — kameraya, GPS-ə, akselerometrə, fayl sisteminə və ya Bluetooth-a giriş mümkün deyil.
React Native daxili Native Module dəsti ilə gəlir: CameraRoll, AsyncStorage, Geolocation, NetInfo və s. Lakin spesifik tapşırıqlar üçün — üçüncü tərəf SDK inteqrasiyası, aparat sensorları ilə iş və ya fon prosesləri — tərtibatçı öz modullarını yaradır. State of React Native 2024 sorğusuna görə, tərtibatçıların 67%-i layihələrində ən azı bir xüsusi Native Module istifadə edir.
Native Module arxitekturası React Native versiyasından asılıdır. Klassik arxitekturada (React Native 0.72 və köhnə) modul Bridge vasitəsilə qoşulur və JS ilə JSON serializasiyası vasitəsilə asinxron əlaqə qurur. Yeni arxitekturada (React Native 0.76+) modul Turbo Module kimi işləyə bilər, JSI istifadə edərək serializasiyasız sinxron giriş təmin edir.
Native Module-in iOS üçün yaradılması RCTBridgeModule protokolunu həyata keçirən Objective-C sinifinin elanı ilə başlayır. RCT_EXPORT_MODULE makrosu modulu Bridge-də qeydiyyatdan keçirir, RCT_EXPORT_METHOD isə JavaScript-dən əlçatan metodu ixrac edir.
// ImageCompressor.m — iOS üçün Native Module
@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
compressImage metodu şəkilə gedən yolu və sıxılma keyfiyyətini (0.0–1.0) qəbul edir, məlumatları nativ tərəfdə emal edir və sıxılmış fayla gedən yolu qaytarır. Əsas üstünlük — sıxılma nativ kodla yerinə yetirilir, bu da JavaScript-dəki analoji əməliyyatdan qat-qat sürətli və yaddaş baxımından səmərəlidir.
Swift modulları üçün sinif və metodlardan əvvəl @objc anotasiyası istifadə olunur ki, onlar Bridge-in işlədiyi Objective-C mühitində əlçatan olsun. Sinif NSObject-dən miras almalı və RCTBridgeModule-i həyata keçirməlidir.
// 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)
}
}
Android-də Native Module ReactContextBaseJavaModule-dən miras alan Java sinifi kimi yaradılır. @ReactMethod anotasiyası metodu Bridge-ə ixrac edir. Nəticəni qaytarmaq üçün com.facebook.react.bridge paketindən Promise interfeysi istifadə olunur.
// 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());
}
}
}
getName() metodu modulun JavaScript-dən əlçatan olacağı adı qaytarır. Verilən nümunədə modul ImageCompressor kimi qeydiyyatdan keçir. @ReactMethod anotasiyası Bridge-ə metodun ixrac edilməli olduğunu göstərir. Əhəmiyyətli: metodlar void olmalı və yalnız Bridge tərəfindən dəstəklənən tipləri qəbul etməlidir: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.
Sinif yaradıldıqdan sonra modul tətbiq paketində qeydiyyatdan keçirilməlidir. Bunun üçün ReactPackage-i həyata keçirən sinif yaradılır və createNativeModules metodunda modullar siyahısına əlavə edilir.
// ImageCompressorPackage.java — modul qeydiyyatı
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();
}
}
Hər iki platforma üçün modullar yaradıldıqdan sonra onlar React Native-də qeydiyyatdan keçirilməlidir. Android üçün paket MainApplication.java-da getPackages() metoduna əlavə edilir. iOS üçün modul RCT_EXPORT_MODULE makrosu vasitəsilə avtomatik qeydiyyatdan keçir, lakin AppDelegate.mm faylında əl ilə qeydiyyat da mümkündür.
// MainApplication.java — paketin React Native-ə əlavə edilməsi
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;
}
};
}
Qeydiyyatdan sonra modul JavaScript-də NativeModules vasitəsilə əlçatan olur. React Native avtomatik olaraq Android üçün getName() və ya iOS üçün RCT_EXPORT_MODULE-də göstərilən modul adını əvəz edir.
// JavaScript-dən Native Module istifadəsi
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('Sıxıldı:', result);
return result;
} catch (error) {
console.error('Sıxılma uğursuz oldu:', error);
throw error;
}
}
Klassik Native Module və Turbo Module-in müqayisəsi yeni layihə üçün hansı yanaşmanın seçiləcəyini anlamağa kömək edir. Hər iki mexanizm nativ koda giriş təmin edir, lakin arxitektura və performans baxımından prinsipial fərqlənir.
| Xüsusiyyət | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| Əlaqə | JSON vasitəsilə asinxron | JSI vasitəsilə sinxron |
| Serializasiya | Hər çağırışda JSON | Məlumat kopyalanması yoxdur |
| Tipizasiya | Əl ilə, generasiyasız | Codegen vasitəsilə avtomatik |
| Yükləmə | Tətbiqin işə salınmasında | Gecikmiş (lazy load) |
| Uyğunluq | Bütün React Native versiyaları | React Native 0.73+ |
React Native 0.72 və köhnə versiyalarında olan mövcud layihələr üçün klassik Native Module əsas seçim olaraq qalır. Yeni layihələr üçün Turbo Module-dən istifadə tövsiyə olunur, xüsusən də nativ metodların tez-tez çağırılması zamanı yüksək performans tələb olunarsa. React Native-in tədricən yenilənməsi ilə icma yeni arxitekturaya tam keçidə doğru hərəkət edir.
Tez-tez verilən suallar
Bəli, Bridge callback-i dəstəkləyir. Promise əvəzinə iOS-da RCTResponseSenderBlock və Android-də Callback geri çağırış funksiyalarından istifadə etmək olar. Lakin Promise müasir standart hesab olunur və yeni modullar üçün tövsiyə edilir.
Native Module adi nativ kod kimi debug edilir — Xcode və ya Android Studio-da breakpoint-lər qoyun. iOS üçün React Native ilə qurma sxemindən, Android üçün Debug konfiqurasiyasından istifadə edin. Giriş nöqtəsi — JS-dən çağırılan metodlardır.
Native Module Bridge vasitəsilə ikili məlumatları (NSData/byte[]), xüsusi obyektləri və funksiyaları dəstəkləmir. Şəkilləri ötürmək üçün fayl yolu və ya base64 sətirindən istifadə edin. JSI vasitəsilə Turbo Module bu məhdudiyyətlərin bir hissəsini aradan qaldırır.
Adətən yox — Native Module API-si sabitdir və geriyə uyğundur. Yeni arxitekturaya (Turbo Module) keçid zamanı modul dekoratorlar vasitəsilə uyğunlaşdırılır, lakin mövcud kod işləməyə davam edir.
iOS-da RCTEventEmitter, Android-də DeviceEventEmitter istifadə edin. Modul hadisə göndərir, JS tərəfi isə react-native-dən NativeEventEmitter vasitəsilə abunə olur. Bu, axın məlumatları və sensor hadisələri üçün faydalıdır.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun