Native Module হল একটি Java বা Objective-C ক্লাস যা প্ল্যাটফর্মের নেটিভ API-গুলিকে React Native-এ JavaScript থেকে অ্যাক্সেসযোগ্য করে তোলে। প্রতিটি মডিউল Bridge-এ রেজিস্টার হয় এবং পদ্ধতিগুলি এক্সপোর্ট করে যা JS কোড থেকে সাধারণ ফাংশনের মতো কল করা যায়। Meta, 2024 অনুসারে, React Native অ্যাপ্লিকেশনে প্ল্যাটফর্ম কোড একীভূত করার প্রধান উপায় Native Module রয়ে গেছে।
মূল বিষয়
Native Module হল React Native-এর একটি আর্কিটেকচারাল উপাদান যা প্ল্যাটফর্মের ভাষায় (iOS-এর জন্য Objective-C/Swift, Android-এর জন্য Java/Kotlin) কোড কার্যকর করতে এবং ফলাফল JavaScript-এ ফেরত দিতে দেয়। Native Module ছাড়া ডিভাইসের নেটিভ ক্ষমতাগুলি — ক্যামেরা, GPS, অ্যাক্সেলেরোমিটার, ফাইল সিস্টেম বা Bluetooth অ্যাক্সেস করা অসম্ভব।
React Native বিল্ট-ইন Native Modules-এর একটি সেট নিয়ে আসে: CameraRoll, AsyncStorage, Geolocation, NetInfo এবং অন্যান্য। তবে নির্দিষ্ট কাজের জন্য — তৃতীয়-পক্ষের SDK একীভূতকরণ, হার্ডওয়্যার সেন্সর নিয়ে কাজ বা ব্যাকগ্রাউন্ড প্রক্রিয়া — ডেভেলপার কাস্টম মডিউল তৈরি করে। State of React Native 2024 জরিপ অনুসারে, 67% ডেভেলপার তাদের প্রকল্পে কমপক্ষে একটি কাস্টম Native Module ব্যবহার করেন।
Native Module আর্কিটেকচার React Native সংস্করণের উপর নির্ভর করে। ক্লাসিক আর্কিটেকচারে (React Native 0.72 এবং পুরানো) মডিউল Bridge-এর মাধ্যমে সংযুক্ত হয় এবং JSON সিরিয়ালাইজেশনের মাধ্যমে JS-এর সাথে অ্যাসিঙ্ক্রোনাসভাবে যোগাযোগ করে। নতুন আর্কিটেকচারে (React Native 0.76+) মডিউল সিরিয়ালাইজেশন ছাড়াই সিঙ্ক্রোনাস অ্যাক্সেসের জন্য JSI ব্যবহার করে Turbo Module হিসেবে কাজ করতে পারে।
iOS-এর জন্য Native Module তৈরি শুরু হয় একটি Objective-C ক্লাস ঘোষণা করার মাধ্যমে যা RCTBridgeModule প্রোটোকল প্রয়োগ করে। RCT_EXPORT_MODULE ম্যাক্রো মডিউলটিকে Bridge-এ রেজিস্টার করে, এবং RCT_EXPORT_METHOD JavaScript থেকে উপলব্ধ একটি পদ্ধতি এক্সপোর্ট করে।
// ImageCompressor.m — iOS-এর জন্য 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 পদ্ধতি একটি ইমেজ পাথ এবং কম্প্রেশন কোয়ালিটি (0.0–1.0) নেয়, নেটিভ সাইডে ডেটা প্রসেস করে এবং কম্প্রেসড ফাইলের পাথ ফেরত দেয়। মূল সুবিধা হল কম্প্রেশন নেটিভ কোড দ্বারা সম্পাদিত হয়, যা সমতুল্য JavaScript অপারেশনের তুলনায় উল্লেখযোগ্যভাবে দ্রুত এবং মেমরি-দক্ষ।
Swift মডিউলের জন্য, ক্লাস এবং পদ্ধতির আগে @objc অ্যানোটেশন ব্যবহার করা হয় যাতে সেগুলি Objective-C রানটাইমের জন্য উপলব্ধ হয় যার সাথে Bridge কাজ করে। ক্লাসটি NSObject থেকে ইনহেরিট করতে হবে এবং 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)
}
}
Android-এ, Native Module ReactContextBaseJavaModule এক্সটেন্ড করে একটি Java ক্লাস হিসেবে তৈরি করা হয়। @ReactMethod অ্যানোটেশন পদ্ধতিটি Bridge-এ এক্সপোর্ট করে। ফলাফল ফেরত দিতে com.facebook.react.bridge থেকে Promise ইন্টারফেস ব্যবহার করা হয়।
// 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() পদ্ধতি মডিউলের নাম ফেরত দেয় যা দিয়ে এটি JavaScript থেকে অ্যাক্সেসযোগ্য হবে। উপরের উদাহরণে, মডিউলটি ImageCompressor হিসেবে রেজিস্টার করা হয়েছে। @ReactMethod অ্যানোটেশন Bridge-কে জানায় যে পদ্ধতিটি এক্সপোর্ট করা উচিত। গুরুত্বপূর্ণ: পদ্ধতিগুলি void হতে হবে এবং শুধুমাত্র Bridge সমর্থিত টাইপগুলি গ্রহণ করবে: String, Boolean, Integer, Double, ReadableArray, ReadableMap, Promise।
মডিউল ক্লাস তৈরি করার পরে, এটি অ্যাপ্লিকেশন প্যাকেজে রেজিস্টার করা আবশ্যক। এর জন্য, ReactPackage প্রয়োগ করে এমন একটি ক্লাস তৈরি করা হয় এবং createNativeModules পদ্ধতিতে মডিউল তালিকায় যুক্ত করা হয়।
// ImageCompressorPackage.java — মডিউল রেজিস্ট্রেশন
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();
}
}
উভয় প্ল্যাটফর্মের জন্য মডিউল তৈরি করার পরে, সেগুলিকে React Native-এ রেজিস্টার করতে হবে। Android-এর জন্য, প্যাকেজটি MainApplication.java-তে getPackages() পদ্ধতিতে যুক্ত করা হয়। iOS-এর জন্য, মডিউলটি স্বয়ংক্রিয়ভাবে RCT_EXPORT_MODULE ম্যাক্রোর মাধ্যমে রেজিস্টার হয়, তবে AppDelegate.mm-এ ম্যানুয়াল রেজিস্ট্রেশনও ব্যবহার করা যেতে পারে।
// MainApplication.java — 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;
}
};
}
রেজিস্ট্রেশনের পরে, মডিউলটি JavaScript-এ NativeModules-এর মাধ্যমে উপলব্ধ হয়। React Native স্বয়ংক্রিয়ভাবে Android-এর জন্য getName() বা iOS-এর জন্য RCT_EXPORT_MODULE-এ উল্লেখিত মডিউল নাম ব্যবহার করে।
// JavaScript থেকে Native Module ব্যবহার
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('সংকুচিত:', result);
return result;
} catch (error) {
console.error('সংকোচন ব্যর্থ:', error);
throw error;
}
}
ক্লাসিক Native Module-এর Turbo Module-এর সাথে তুলনা বুঝতে সাহায্য করে যে নতুন প্রকল্পের জন্য কোন পদ্ধতি বেছে নেওয়া উচিত। উভয় প্রক্রিয়াই নেটিভ কোডে অ্যাক্সেস প্রদান করে, কিন্তু আর্কিটেকচার এবং পারফরম্যান্সে মৌলিকভাবে ভিন্ন।
| বৈশিষ্ট্য | Native Module (Bridge) | Turbo Module (JSI) |
|---|---|---|
| যোগাযোগ | JSON-এর মাধ্যমে অ্যাসিঙ্ক্রোনাস | JSI-এর মাধ্যমে সিঙ্ক্রোনাস |
| সিরিয়ালাইজেশন | প্রতি কলেই JSON | ডেটা কপি না করে |
| টাইপিং | ম্যানুয়াল, জেনারেশন ছাড়া | Codegen-এর মাধ্যমে অটো |
| লোডিং | অ্যাপ্লিকেশন initialization-এ | লেজি লোড (lazy load) |
| সামঞ্জস্যতা | সব React Native সংস্করণ | React Native 0.73+ |
React Native 0.72 এবং পুরানো সংস্করণে বিদ্যমান প্রকল্পগুলির জন্য, ক্লাসিক Native Modules প্রধান পছন্দ রয়ে গেছে। নতুন প্রকল্পগুলির জন্য Turbo Module সুপারিশ করা হয়, বিশেষ করে যদি ঘন ঘন নেটিভ পদ্ধতি কলের জন্য উচ্চ কর্মক্ষমতা প্রয়োজন হয়। React Native-এর ক্রমাগত আপডেটের সাথে, সম্প্রদায় নতুন আর্কিটেকচারে সম্পূর্ণ রূপান্তরের দিকে এগিয়ে যাচ্ছে।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
হ্যাঁ, Bridge callback সমর্থন করে। Promise-এর পরিবর্তে iOS-এ RCTResponseSenderBlock এবং Android-এ Callback ফাংশন ব্যবহার করা যেতে পারে। তবে Promise-কে আধুনিক মান হিসাবে বিবেচনা করা হয় এবং নতুন মডিউলের জন্য সুপারিশ করা হয়।
Native Module সাধারণ নেটিভ কোডের মতো ডিবাগ করা হয় — Xcode বা Android Studio-তে ব্রেকপয়েন্ট সেট করুন। iOS-এর জন্য, React Native-এর সাথে বিল্ড স্কিম ব্যবহার করুন; Android-এর জন্য, Debug কনফিগারেশন ব্যবহার করুন। এন্ট্রি পয়েন্ট হল JS থেকে কল করা পদ্ধতিগুলি।
Bridge-এর মাধ্যমে Native Module বাইনারি ডেটা (NSData/byte[]), কাস্টম অবজেক্ট এবং ফাংশন সমর্থন করে না। ছবির জন্য, ফাইল পাথ বা base64 স্ট্রিং ব্যবহার করুন। JSI-এর মাধ্যমে Turbo Module এই সীমাবদ্ধতার কিছু দূর করে।
সাধারণত না — Native Module API স্থিতিশীল এবং পশ্চাৎ-সামঞ্জস্যপূর্ণ। নতুন আর্কিটেকচারে (Turbo Module) রূপান্তর করার সময়, মডিউল ডেকোরেটরের মাধ্যমে অভিযোজিত হয়, তবে বিদ্যমান কোড কাজ করতে থাকে।
iOS-এ RCTEventEmitter বা Android-এ DeviceEventEmitter ব্যবহার করুন। মডিউল একটি ইভেন্ট পাঠায়, এবং JS পক্ষ react-native থেকে NativeEventEmitter-এর মাধ্যমে সাবস্ক্রাইব করে। এটি স্ট্রিমিং ডেটা এবং সেন্সর ইভেন্টের জন্য উপযোগী।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন