7.3 KiB
7.3 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| mobile-native-module-bridging-deep | Native Module Bridging — RN / Flutter / KMP | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
Native Module Bridging Deep
Cross-platform 가 native API 호출. RN JSI, Flutter platform channel, KMP expect/actual, FFI.
📖 핵심 개념
- Cross-platform 가 매 native 의 wrap.
- Bridge / channel 가 cost.
- Modern: JSI (RN), MethodChannel (Flutter).
- KMP = native interop.
💻 코드 패턴
React Native New Architecture (JSI)
// NativeMyModule.h (TurboModule)
class NativeMyModule : public TurboModule {
public:
facebook::jsi::Value getDeviceInfo(facebook::jsi::Runtime &runtime);
};
// JS
import NativeMyModule from './NativeMyModule';
const info = NativeMyModule.getDeviceInfo();
// → JSI = direct call. 빠름.
→ Old: JSON bridge (slow). New: JSI (synchronous, fast).
iOS (Swift)
// MyModule.swift
@objc(MyModule)
class MyModule: NSObject {
@objc func getDeviceInfo(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
let info = ['model': UIDevice.current.model]
resolve(info)
}
@objc static func requiresMainQueueSetup() -> Bool {
return true
}
}
Android (Kotlin)
class MyModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName() = "MyModule"
@ReactMethod
fun getDeviceInfo(promise: Promise) {
promise.resolve(mapOf("model" to Build.MODEL))
}
}
TurboModule (modern RN)
// TS spec
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
getDeviceInfo(): Object;
multiply(a: number, b: number): number;
}
export default TurboModuleRegistry.getEnforcing<Spec>('MyModule');
→ Code generated. Type-safe.
Flutter platform channel
// lib/my_module.dart
import 'package:flutter/services.dart';
class MyModule {
static const channel = MethodChannel('my_module');
static Future<Map> getDeviceInfo() async {
return await channel.invokeMethod('getDeviceInfo');
}
}
Flutter iOS (Swift)
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(...) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: 'my_module', binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { call, result in
if call.method == 'getDeviceInfo' {
result(['model': UIDevice.current.model])
}
}
}
}
Flutter Pigeon (type-safe)
// pigeons/messages.dart
@HostApi()
abstract class MyApi {
@async
Map<String, String> getDeviceInfo();
}
→ Codegen 가 native + Dart side.
KMP (expect / actual)
// commonMain
expect class Platform() {
val name: String
}
// androidMain
actual class Platform {
actual val name = 'Android ${Build.VERSION.SDK_INT}'
}
// iosMain
actual class Platform {
actual val name = 'iOS ${UIDevice.currentDevice.systemVersion}'
}
KMP iOS interop
// iosMain
import platform.UIKit.UIDevice
import platform.Foundation.NSDate
fun getDate() = NSDate()
fun getDevice() = UIDevice.currentDevice
→ Apple SDK 가 Kotlin 안.
Swift / C interop
// Swift 의 C function call
import Darwin
let pid = getpid()
// Swift 가 C struct
let buf = UnsafeMutablePointer<Int8>.allocate(capacity: 100)
strcpy(buf, 'hello')
Rust FFI
#[no_mangle]
pub extern 'C' fn add(a: i32, b: i32) -> i32 {
a + b
}
// C header
int32_t add(int32_t a, int32_t b);
→ iOS / Android 가 Rust shared library.
React Native + Rust
// react-native-uniffi.
// → Rust → JSI native module.
→ Cryptography, ML inference 친화.
Performance
JSON bridge (옛 RN): 10-100 ms / call.
JSI / TurboModule: < 1 ms.
Flutter platform channel: ~1 ms.
KMP: ~ direct call (no bridge).
FFI: native speed.
→ Modern = bridge cost 거의 X.
Codegen
RN: Codegen (TS spec → C++ binding).
Flutter: Pigeon.
KMP: 자체 (no codegen).
→ Type-safe + 빠른 development.
Async vs sync
JSI (RN): sync 가능.
Platform channel (Flutter): async 만.
KMP: 매 (suspend OK).
→ Sync 가 약간 빠름 가, deadlock 위험.
Threading
Native callback 가 main thread or background:
- iOS: dispatch_async.
- Android: Handler / Coroutine.
- 잘못 = crash.
Plugin ecosystem
RN:
- npm install + auto-link (RN 0.60+).
- TurboModule 가 modern.
Flutter:
- pub.dev.
- Plugin 의 Dart + native.
KMP:
- Maven / CocoaPods.
- Compose Multiplatform.
When NOT bridge?
- Pure UI: framework UI 가 충분.
- Network: HTTP client (cross-platform).
- Storage: SQLite / KV (cross-platform library).
→ Native API 만 (Bluetooth, sensor, AR) bridging.
Real native vs bridged
Camera:
- Native: AVCaptureSession (iOS), CameraX (Android).
- Bridged: react-native-camera, image_picker (Flutter).
→ 매 platform 의 nuance.
Bridge 의 quality = library 따라.
Bluetooth (예)
RN: react-native-ble-plx.
Flutter: flutter_blue_plus.
KMP: kable.
→ 매 가 native API 의 wrapper.
ML (Core ML / TFLite)
RN: react-native-fast-tflite.
Flutter: tflite_flutter.
KMP: 자체 wrap.
→ Performance 가 native speed.
Debug
Native crash:
- iOS: Xcode debug + symbol.
- Android: Logcat + adb.
- Flutter: flutter logs.
- RN: react-native log.
→ Native crash 가 cross-platform 의 어려움.
Cross-platform library
- SQLite (모든).
- Realm (RN, Flutter).
- WatermelonDB (RN).
- Drift (Flutter).
- SQLDelight (KMP).
→ 1 library, 모든 platform.
Type safety
TurboModule (RN): TS spec → 자동 type.
Pigeon (Flutter): Dart spec → 자동 type.
KMP: Kotlin types 가 native.
→ Manual writing 가 typo / drift 위험.
Production tips
1. TurboModule / Pigeon (codegen).
2. Async wherever possible.
3. Native crash report (Sentry).
4. Test 가 매 platform.
5. Plugin 신중 선택 (maintenance).
6. Native module version pin.
Common 함정
- Main thread block: ANR / freeze.
- Memory leak (callback ref).
- Native crash 가 silent.
- Plugin 의 maintainer 0.
- Old bridge (RN 0.60 이하).
- Synchronous on Flutter: 안 됨.
🤔 의사결정 기준
| Cross-platform | Native bridge |
|---|---|
| RN | TurboModule |
| Flutter | Pigeon (Dart + native) |
| KMP | expect/actual |
| Rust shared | FFI |
| Multi-FW | KMP |
| Native UI 도 | 매 native UI separate |
❌ 안티패턴
- Old RN bridge: slow.
- Sync from main: ANR.
- Manual type binding: drift.
- Plugin 가 unmaintained: vulnerable.
- Memory leak in callback: crash.
🤖 LLM 활용 힌트
- TurboModule (RN), Pigeon (Flutter), expect/actual (KMP).
- Codegen 가 type-safe + 빠른 dev.
- FFI 가 Rust / C interop.
- Native API 만 bridge (UI X).