Ang Native Module ay isang Java o Objective-C class na ginagawang accessible ang native API ng platform mula sa JavaScript sa React Native. Ang bawat module ay nagrerehistro sa Bridge at nag-e-export ng mga method na maaaring tawagin mula sa JS code tulad ng mga ordinaryong function. Ayon sa Meta, 2024, ang Native Module ay nananatiling pangunahing paraan ng pagsasama ng platform code sa mga React Native application.
Mga Pangunahing Punto
Native Module ay isang arkitektural na elemento ng React Native na nagpapahintulot sa pag-execute ng code sa platform language (Objective-C/Swift para sa iOS, Java/Kotlin para sa Android) at pagbalik ng resulta sa JavaScript. Kung walang Native Module, imposibleng ma-access ang native capabilities ng device — camera, GPS, accelerometer, file system o Bluetooth.
Ang React Native ay may kasamang set ng built-in na Native Module: CameraRoll, AsyncStorage, Geolocation, NetInfo at iba pa. Ngunit para sa mga spesipikong gawain — pagsasama ng third-party SDK, pagtatrabaho sa hardware sensors o background na proseso — gumagawa ang developer ng sarili niyang mga module. Ayon sa State of React Native 2024 survey, 67% ng mga developer ay gumagamit ng kahit isang custom na Native Module sa kanilang mga proyekto.
Ang arkitektura ng Native Module ay nakadepende sa bersyon ng React Native. Sa klasikong arkitektura (React Native 0.72 at mas luma) ang module ay kumokonekta sa pamamagitan ng Bridge at nakikipag-ugnayan sa JS nang asynchronously sa pamamagitan ng JSON serialization. Sa bagong arkitektura (React Native 0.76+) ang module ay maaaring gumana bilang Turbo Module, gamit ang JSI para sa synchronous na access nang walang serialization.
Ang paggawa ng Native Module para sa iOS ay nagsisimula sa pagdedeklara ng Objective-C class na nag-i-implement ng RCTBridgeModule protocol. Ang macro na RCT_EXPORT_MODULE ay nagrerehistro ng module sa Bridge, at ang RCT_EXPORT_METHOD ay nag-e-export ng method na accessible mula sa JavaScript.
// ImageCompressor.m — Native Module para sa 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
Ang method na compressImage ay tumatanggap ng path sa image at compression quality (0.0–1.0), nagproseso ng data sa native side at bumabalik ng path sa compressed file. Ang pangunahing bentahe — ang compression ay ginagawa ng native code, na mas mabilis at mas memory-efficient kumpara sa katulad na operasyon sa JavaScript.
Para sa Swift modules, ginagamit ang annotation na @objc bago ang class at methods upang maging accessible ang mga ito sa Objective-C runtime na ginagamit ng Bridge. Ang class ay dapat magmana sa NSObject at mag-implement ng 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)
}
}
Sa Android ang Native Module ay ginagawa bilang Java class na nagmamana sa ReactContextBaseJavaModule. Ang annotation na @ReactMethod ay nag-e-export ng method sa Bridge. Para sa pagbalik ng resulta, ginagamit ang Promise interface mula sa 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());
}
}
}
Ang method na getName() ay bumabalik ng pangalan ng module kung saan ito magiging accessible mula sa JavaScript. Sa ibinigay na halimbawa, ang module ay nagrerehistro bilang ImageCompressor. Ang annotation na @ReactMethod ay nagpapahiwatig sa Bridge na ang method ay dapat i-export. Mahalaga: ang mga method ay dapat void at tumanggap lamang ng mga uri na sinusuportahan ng Bridge: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise.
Pagkatapos gawin ang class, ang module ay dapat irehistro sa application package. Para dito, ginagawa ang isang class na nag-i-implement ng ReactPackage at idinadagdag sa listahan ng modules sa method na createNativeModules.
// ImageCompressorPackage.java — pagrehistro ng module
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();
}
}
Pagkatapos gawin ang modules para sa parehong platform, kailangan silang irehistro sa React Native. Para sa Android, ang package ay idinadagdag sa MainApplication.java sa method na getPackages(). Para sa iOS, ang module ay awtomatikong nagrerehistro sa pamamagitan ng macro na RCT_EXPORT_MODULE, ngunit maaari ring gamitin ang manual na pagrehistro sa file na AppDelegate.mm.
// MainApplication.java — pagdaragdag ng package sa 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;
}
};
}
Pagkatapos ng pagrehistro, ang module ay nagiging accessible sa JavaScript sa pamamagitan ng NativeModules. Awtomatikong pinapalitan ng React Native ang pangalan ng module na tinukoy sa getName() para sa Android o sa RCT_EXPORT_MODULE para sa iOS.
// Paggamit ng Native Module mula sa JavaScript
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('Compressed:', result);
return result;
} catch (error) {
console.error('Nabigo ang compression:', error);
throw error;
}
}
Ang paghahambing ng klasikong Native Module at Turbo Module ay tumutulong upang maunawaan kung aling approach ang pipiliin para sa bagong proyekto. Ang parehong mekanismo ay nagbibigay ng access sa native code, ngunit nagkakaiba nang pundamental sa arkitektura at performance.
| Katangian | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| Komunikasyon | Asynchronous sa pamamagitan ng JSON | Synchronous sa pamamagitan ng JSI |
| Serialization | JSON sa bawat tawag | Walang pagkopya ng data |
| Tipification | Manual, walang generation | Awtomatiko sa pamamagitan ng Codegen |
| Pag-load | Sa initialization ng application | Lazy load |
| Pagkakatugma | Lahat ng bersyon ng React Native | React Native 0.73+ |
Para sa mga umiiral na proyekto sa React Native 0.72 at mas luma, ang klasikong Native Module ay nananatiling pangunahing pagpipilian. Para sa mga bagong proyekto, inirerekomenda ang paggamit ng Turbo Module, lalo na kung kinakailangan ang mataas na performance sa madalas na pagtawag ng native methods. Sa unti-unting pag-update ng React Native, ang komunidad ay gumagalaw patungo sa kumpletong paglipat sa bagong arkitektura.
Mga Madalas Itanong
Oo, sinusuportahan ng Bridge ang callback. Sa halip na Promise, maaaring gamitin ang callback functions na RCTResponseSenderBlock sa iOS at Callback sa Android. Gayunpaman, ang Promise ay itinuturing na modernong pamantayan at inirerekomenda para sa mga bagong module.
Ang Native Module ay dina-debug tulad ng ordinaryong native code — magtakda ng mga breakpoint sa Xcode o Android Studio. Para sa iOS gamitin ang build scheme na may React Native, para sa Android — Debug configuration. Ang entry point — mga method na tinawag mula sa JS.
Native Module sa pamamagitan ng Bridge ay hindi sumusuporta ng binary data (NSData/byte[]), custom objects at functions. Para sa pagpapadala ng mga imahe, gamitin ang file path o base64 string. Ang Turbo Module sa pamamagitan ng JSI ay nag-aalis ng ilan sa mga limitasyong ito.
Karaniwan hindi — ang Native Module API ay stable at backward compatible. Kapag lumipat sa bagong arkitektura (Turbo Module), ang module ay ini-adapt sa pamamagitan ng decorators, ngunit ang umiiral na code ay patuloy na gumagana.
Gamitin ang RCTEventEmitter sa iOS o DeviceEventEmitter sa Android. Ang module ay nagpapadala ng event, at ang JS side ay nagse-subscribe sa pamamagitan ng NativeEventEmitter mula sa react-native. Ito ay kapaki-pakinabang para sa streaming data at sensor events.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din