[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
---
|
||||
id: mobile-native-module-bridging-deep
|
||||
title: Native Module Bridging — RN / Flutter / KMP
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [mobile, rn, flutter, vibe-coding]
|
||||
tech_stack: { language: "TS / Swift / Kotlin", applicable_to: ["Mobile"] }
|
||||
applied_in: []
|
||||
aliases: [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)
|
||||
```cpp
|
||||
// NativeMyModule.h (TurboModule)
|
||||
class NativeMyModule : public TurboModule {
|
||||
public:
|
||||
facebook::jsi::Value getDeviceInfo(facebook::jsi::Runtime &runtime);
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
// JS
|
||||
import NativeMyModule from './NativeMyModule';
|
||||
|
||||
const info = NativeMyModule.getDeviceInfo();
|
||||
// → JSI = direct call. 빠름.
|
||||
```
|
||||
|
||||
→ Old: JSON bridge (slow).
|
||||
New: JSI (synchronous, fast).
|
||||
|
||||
### iOS (Swift)
|
||||
```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)
|
||||
```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
|
||||
// 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
|
||||
```dart
|
||||
// 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)
|
||||
```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)
|
||||
```dart
|
||||
// pigeons/messages.dart
|
||||
@HostApi()
|
||||
abstract class MyApi {
|
||||
@async
|
||||
Map<String, String> getDeviceInfo();
|
||||
}
|
||||
```
|
||||
|
||||
→ Codegen 가 native + Dart side.
|
||||
|
||||
### KMP (expect / actual)
|
||||
```kotlin
|
||||
// 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
|
||||
```kotlin
|
||||
// iosMain
|
||||
import platform.UIKit.UIDevice
|
||||
import platform.Foundation.NSDate
|
||||
|
||||
fun getDate() = NSDate()
|
||||
fun getDevice() = UIDevice.currentDevice
|
||||
```
|
||||
|
||||
→ Apple SDK 가 Kotlin 안.
|
||||
|
||||
### Swift / C interop
|
||||
```swift
|
||||
// Swift 의 C function call
|
||||
import Darwin
|
||||
|
||||
let pid = getpid()
|
||||
```
|
||||
|
||||
```swift
|
||||
// Swift 가 C struct
|
||||
let buf = UnsafeMutablePointer<Int8>.allocate(capacity: 100)
|
||||
strcpy(buf, 'hello')
|
||||
```
|
||||
|
||||
### Rust FFI
|
||||
```rust
|
||||
#[no_mangle]
|
||||
pub extern 'C' fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
// C header
|
||||
int32_t add(int32_t a, int32_t b);
|
||||
```
|
||||
|
||||
→ iOS / Android 가 Rust shared library.
|
||||
|
||||
### React Native + Rust
|
||||
```ts
|
||||
// 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).
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Mobile_RN_New_Architecture]]
|
||||
- [[Mobile_KMP_Deep]]
|
||||
- [[Mobile_Flutter_Patterns]]
|
||||
Reference in New Issue
Block a user