Files
2nd/10_Wiki/Topics/Coding/Mobile_Native_Module_Bridging_Deep.md
T
2026-05-10 22:08:15 +09:00

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
mobile
rn
flutter
vibe-coding
language applicable_to
TS / Swift / Kotlin
Mobile
native module
JSI
bridge
platform channels
FFI
Kotlin/Native
Swift/C interop

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).

🔗 관련 문서