Native Module, Java veya Objective-C sınıfıdır ve React Native'de JavaScript'ten platformun yerel API'lerine erişim sağlar. Her modül Bridge'e kaydedilir ve JS kodundan normal işlevler gibi çağrılabilen yöntemleri dışa aktarır. Meta, 2024'ye göre, Native Module React Native uygulamalarına platform kodunu entegre etmenin ana yolu olmaya devam etmektedir.
Önemli Noktalar
Native Module, React Native'in platform dilinde (iOS için Objective-C/Swift, Android için Java/Kotlin) kod yürütmeye ve sonucu JavaScript'e döndürmeye izin veren mimari bir öğesidir. Native Module olmadan cihazın yerel yeteneklerine — kamera, GPS, ivmeölçer, dosya sistemi veya Bluetooth — erişmek imkansızdır.
React Native, yerleşik Native Module'lerle birlikte gelir: CameraRoll, AsyncStorage, Geolocation, NetInfo ve diğerleri. Ancak belirli görevler için — üçüncü taraf SDK entegrasyonu, donanım sensörleriyle çalışma veya arka plan işlemleri — geliştirici özel modüller oluşturur. State of React Native 2024 anketine göre, geliştiricilerin %67'si projelerinde en az bir özel Native Module kullanmaktadır.
Native Module mimarisi React Native sürümüne bağlıdır. Klasik mimaride (React Native 0.72 ve öncesi) modül Bridge aracılığıyla bağlanır ve JSON serileştirme yoluyla JS ile asenkron olarak iletişim kurar. Yeni mimaride (React Native 0.76+) modül, serileştirme olmadan senkron erişim için JSI kullanarak Turbo Module olarak çalışabilir.
iOS için Native Module oluşturma, RCTBridgeModule protokolünü uygulayan bir Objective-C sınıfı bildirmekle başlar. RCT_EXPORT_MODULE makrosu modülü Bridge'e kaydeder ve RCT_EXPORT_METHOD JavaScript'ten kullanılabilir bir yöntemi dışa aktarır.
// ImageCompressor.m — iOS için 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 yöntemi bir resim yolu ve sıkıştırma kalitesi (0.0–1.0) alır, verileri yerel tarafta işler ve sıkıştırılmış dosyanın yolunu döndürür. Temel avantaj, sıkıştırmanın yerel kod tarafından gerçekleştirilmesidir ki bu, eşdeğer JavaScript işleminden önemli ölçüde daha hızlı ve bellek açısından daha verimlidir.
Swift modülleri için, sınıf ve yöntemlerden önce @objc ek açıklaması kullanılır, böylece Bridge'in çalıştığı Objective-C çalışma zamanı tarafından kullanılabilir olurlar. Sınıf, NSObject'ten miras almalı ve RCTBridgeModule'u uygulamalıdır.
// ImageCompressor.swift — Swift Yerel Modülü
@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'de Native Module, ReactContextBaseJavaModule'u genişleten bir Java sınıfı olarak oluşturulur. @ReactMethod ek açıklaması yöntemi Bridge'e aktarır. Sonuçları döndürmek için com.facebook.react.bridge'den Promise arayüzü kullanılır.
// 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() yöntemi, JavaScript'ten erişilebilir olacağı modül adını döndürür. Yukarıdaki örnekte modül ImageCompressor olarak kaydedilmiştir. @ReactMethod ek açıklaması Bridge'e yöntemin dışa aktarılması gerektiğini bildirir. Önemli: yöntemler void olmalı ve yalnızca Bridge tarafından desteklenen türleri kabul etmelidir: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.
Modül sınıfını oluşturduktan sonra, uygulama paketinde kaydedilmelidir. Bunun için ReactPackage uygulayan bir sınıf oluşturulur ve createNativeModules yönteminde modül listesine eklenir.
// ImageCompressorPackage.java — modül kaydı
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();
}
}
Her iki platform için modüller oluşturulduktan sonra, React Native'e kaydedilmeleri gerekir. Android için paket, MainApplication.java'da getPackages() yöntemine eklenir. iOS için modül, RCT_EXPORT_MODULE makrosu aracılığıyla otomatik olarak kaydedilir, ancak AppDelegate.mm'de manuel kayıt da kullanılabilir.
// MainApplication.java — React Native'e paket ekleme
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;
}
};
}
Kayıttan sonra modül, JavaScript'te NativeModules aracılığıyla kullanılabilir hale gelir. React Native, Android için getName() veya iOS için RCT_EXPORT_MODULE'de belirtilen modül adını otomatik olarak kullanır.
// JavaScript'ten Native Module Kullanımı
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ıkıştırıldı:', result);
return result;
} catch (error) {
console.error('Sıkıştırma başarısız:', error);
throw error;
}
}
Klasik Native Module ile Turbo Module karşılaştırması, yeni bir proje için hangi yaklaşımın seçileceğini anlamaya yardımcı olur. Her iki mekanizma da yerel koda erişim sağlar, ancak mimari ve performans açısından temelde farklılık gösterir.
| Özellik | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| İletişim | JSON ile asenkron | JSI ile senkron |
| Serileştirme | Her çağrıda JSON | Veri kopyalamadan |
| Tiplendirme | Manuel, üretim olmadan | Codegen ile otomatik |
| Yükleme | Uygulama başlatmada | Tembel yükleme (lazy load) |
| Uyumluluk | Tüm React Native sürümleri | React Native 0.73+ |
React Native 0.72 ve öncesindeki mevcut projeler için klasik Native Module'ler ana seçim olmaya devam etmektedir. Yeni projeler için, özellikle sık yerel yöntem çağrılarında yüksek performans gerekiyorsa, Turbo Module önerilir. React Native'in kademeli güncellemesiyle birlikte topluluk, yeni mimariye tam geçişe doğru ilerlemektedir.
Sıkça Sorulan Sorular
Evet, Bridge callback'leri destekler. Promise yerine iOS'ta RCTResponseSenderBlock callback işlevleri ve Android'de Callback kullanılabilir. Ancak Promise, modern standart olarak kabul edilir ve yeni modüller için önerilir.
Native Module, normal yerel kod gibi hata ayıklanır — Xcode veya Android Studio'da kesme noktaları ayarlayın. iOS için React Native ile derleme şemasını kullanın; Android için Debug yapılandırmasını kullanın. Giriş noktası, JS'den çağrılan yöntemlerdir.
Bridge aracılığıyla Native Module, ikili verileri (NSData/byte[]), özel nesneleri ve işlevleri desteklemez. Görseller için bir dosya yolu veya base64 dizesi kullanın. JSI aracılığıyla Turbo Module bu sınırlamaların bazılarını kaldırır.
Genellikle hayır — Native Module API'si kararlı ve geriye dönük uyumludur. Yeni mimariye (Turbo Module) geçiş yaparken modül dekoratörler aracılığıyla uyarlanır, ancak mevcut kod çalışmaya devam eder.
iOS'ta RCTEventEmitter veya Android'de DeviceEventEmitter kullanın. Modül bir olay gönderir ve JS tarafı react-native'den NativeEventEmitter aracılığıyla abone olur. Bu, akış verileri ve sensör olayları için kullanışlıdır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun