Skip to content
Published on

크로스플랫폼 모바일 개발 2026 심층 가이드 — React Native·Flutter·Expo·Capacitor·Tauri 2·Kotlin Multiplatform·Compose MP·.NET MAUI·NativeScript·Lynx

Authors

프롤로그 — 2026년, "한 번 짜서 둘 다"라는 약속의 새 국면

2015년 React Native가 처음 등장했을 때, "한 번 짜서 iOS·Android 둘 다 돌린다"는 약속은 거대했다. Facebook이 직접 만들고, JSX로 짜고, JavaScript 브릿지를 통해 네이티브 뷰를 조작한다. 그것은 약속이었지만 동시에 한계였다. 브릿지는 비동기였고, 직렬화 비용이 컸으며, 60fps의 부드러운 애니메이션은 늘 신경 써야 했다.

2026년 5월, 풍경이 바뀌었다.

  • React Native 0.76 (Meta, 2024년 10월 출시 → 2026년 안정 운영기) 의 New Architecture(Fabric 렌더러 + TurboModules + JSI)가 모든 신규 앱의 기본값이 되었다. 브릿지 직렬화가 사라지고, 동기 네이티브 호출이 가능해졌다.
  • Flutter 3.27 (Google, 2024년 말 출시 → 2026년 운영기) 은 Impeller 렌더러를 iOS와 Android 모두에서 기본값으로 만들었다. Skia 기반의 동적 셰이더 컴파일이 사라지고, 미리 컴파일된 셰이더로 첫 프레임의 끊김(jank)이 거의 사라졌다.
  • Tauri 2.0 (Tauri team, 2024년 10월) 이 iOS·Android 모바일 타깃을 정식 지원하기 시작했다. "Rust로 모바일"이 처음으로 실현 가능해졌다.
  • JetBrains Kotlin Multiplatform 2.1 + Compose Multiplatform 1.7 은 iOS 공유 UI를 안정 단계로 끌어올렸다.
  • ByteDance Lynx 가 2025년 3월 오픈소스로 공개됐다. TikTok·Douyin의 라이브 커머스·미니앱을 굴리던 사내 프레임워크가 외부에 처음 풀린 사건이다.

크로스플랫폼은 더 이상 단일 정답이 없다. 이 글은 2026년의 모바일 크로스플랫폼 스택을 한 호흡으로 정리한다.


1장 · 크로스플랫폼이 푸는 본질 문제

iOS는 Swift/Objective-C + UIKit/SwiftUI를 쓰고, Android는 Kotlin/Java + Views/Jetpack Compose를 쓴다. 두 플랫폼은 언어·UI 툴킷·툴체인·배포 채널이 모두 다르다. "비즈니스 로직과 화면을 한 번만 짜고 양쪽에서 돌린다"는 욕구는 그래서 끈질기다.

크로스플랫폼은 다섯 가지 다른 전략으로 이 문제를 푼다.

  • JavaScript 브릿지(전통 React Native): JS 코드가 네이티브 뷰를 원격 제어한다.
  • JSI 직접 호출(현대 React Native, New Architecture): JS와 네이티브가 같은 메모리·동기 호출.
  • 자체 렌더러(Flutter, Lynx): 플랫폼 뷰를 안 쓰고 캔버스에 직접 그린다.
  • WebView(Capacitor, Ionic, Cordova): 웹 UI를 네이티브 컨테이너에 띄운다.
  • 공유 비즈니스 로직(Kotlin Multiplatform, KMP): 비즈니스 코드는 공유, UI는 플랫폼 네이티브.

선택은 도메인 의존이다. 게임은 자체 렌더러를 선호하고, 사내 도구는 WebView로 충분하며, 메신저·이커머스는 New Architecture RN 또는 KMP 어느 한쪽으로 수렴한다.


2장 · React Native New Architecture — JSI·Fabric·TurboModules

React Native 0.76에서 안정화된 New Architecture는 세 부분이다.

  • JSI (JavaScript Interface): V8/Hermes와 C++ 사이의 얇은 인터페이스. JS 객체가 C++ HostObject로 직접 노출되어 직렬화 없이 호출이 가능하다.
  • Fabric: 새 렌더러. JS가 React 트리를 만들고, 그 트리가 C++ Shadow Tree로 변환되어 메인 스레드에서 직접 네이티브 뷰로 커밋된다. 동기 레이아웃 가능.
  • TurboModules: 네이티브 모듈을 JSI 기반으로 재작성. 모듈은 lazy하게 초기화되고, 호출은 동기/비동기 모두 가능하다.

전통 RN에서는 모든 호출이 "직렬화 → JSON → 네이티브 디시리얼라이즈 → 비동기 콜백"이었다면, New Architecture는 JS가 직접 C++ 포인터를 잡고 함수를 호출한다. 핫 리로드는 여전히 빠르고, 디버깅은 React DevTools 그대로다.

// TurboModule 정의: spec/NativeMathModule.ts
import type { TurboModule } from 'react-native'
import { TurboModuleRegistry } from 'react-native'

export interface Spec extends TurboModule {
  add(a: number, b: number): number
  factorial(n: number): Promise<number>
  getDeviceLocale(): string
}

export default TurboModuleRegistry.getEnforcing<Spec>('NativeMathModule')
// 사용: App.tsx
import NativeMathModule from './spec/NativeMathModule'

export default function App() {
  // 동기 호출 — 브릿지 없이 직접 네이티브 함수를 호출한다
  const sum = NativeMathModule.add(2, 3)
  const locale = NativeMathModule.getDeviceLocale()
  return null
}

codegen 단계가 Spec 인터페이스를 읽어 iOS의 Objective-C++ 헤더와 Android의 Java/Kotlin 인터페이스를 자동 생성한다. 옛 NativeModules보다 타입 안전성이 비약적으로 좋아졌다.


3장 · Hermes — JavaScriptCore에서 자체 엔진으로

Hermes는 Meta가 모바일 RN을 위해 만든 JS 엔진이다. 2026년 현재 RN의 기본 엔진이다.

  • 바이트코드 사전 컴파일(AOT)로 시작 시간이 짧다.
  • 가비지 컬렉터가 모바일에 맞게 튜닝됐다(짧은 stop-the-world).
  • V8보다 메모리 풋프린트가 작다.
  • ES2015+ 대부분 지원, Proxy·정규식 일부 제약이 있다.

전통적으로 iOS RN은 JavaScriptCore(JSC)를 썼고, Android는 V8 또는 JSC였다. Hermes는 두 플랫폼에서 동일한 동작을 보장하면서도 시작 시간을 절반 가까이 줄였다. <200ms 콜드 스타트가 가능한 이유다.


4장 · Flutter — Skia에서 Impeller로

Flutter는 처음부터 자체 렌더러를 가진 프레임워크였다. 플랫폼의 UIKit·View를 쓰지 않고, Skia로 직접 픽셀을 그린다. 2026년의 변화는 렌더 엔진이 Skia에서 Impeller로 옮겨갔다는 것이다.

  • Skia: Chromium의 2D 그래픽 엔진. Flutter 초기부터 썼다. 강점은 호환성과 성숙도. 약점은 런타임 셰이더 컴파일로 인한 첫 프레임 끊김.
  • Impeller: Flutter 팀이 자체 개발한 렌더러. 셰이더를 빌드 타임에 미리 컴파일하고, Metal(iOS)·Vulkan(Android)을 직접 사용. 첫 프레임 jank가 거의 사라졌다.

Flutter 3.27부터 iOS·Android 모두 Impeller가 기본이다. 일부 복잡한 셰이더 효과는 여전히 Skia 폴백을 쓰지만, 일반 앱의 99%는 Impeller에서 부드럽게 돈다.

// Flutter: 기본 Material 앱
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '2026 Cross-Platform Demo',
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _count = 0;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter')),
      body: Center(child: Text('Count: $_count', style: const TextStyle(fontSize: 32))),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() => _count++),
        child: const Icon(Icons.add),
      ),
    );
  }
}

Dart는 AOT 컴파일되어 네이티브 머신 코드로 변환되므로, JIT 워밍업이 없다. 시작은 빠르고, 60fps 유지가 비교적 쉽다. 단점은 바이너리 크기가 크다는 것 — 기본 Flutter 앱이 iOS에서 약 15MB, Android에서 8-10MB를 차지한다.


5장 · Expo — RN 개발자 경험의 사실상 표준

Expo는 처음에는 "RN 시작하기 쉬운 도구"였지만, 2026년에는 RN의 사실상 표준 개발 환경이 됐다. Expo SDK 53(2026년 상반기)의 핵심 컴포넌트:

  • EAS Build: 클라우드 빌드 서비스. iOS는 Mac이 필요하지만 EAS는 클라우드에서 처리한다.
  • EAS Submit: App Store / Play Store 자동 제출.
  • EAS Update: OTA(Over-the-air) 업데이트. 네이티브 변경 없는 JS 업데이트를 코드 푸시한다.
  • Expo Router: 파일 기반 라우팅. Next.js와 비슷한 app/ 디렉터리 구조를 RN에 도입.
  • Expo Atlas: 번들 분석 도구. 어떤 모듈이 번들 크기를 차지하는지 시각화.
  • Expo Modules: TurboModule 작성을 더 쉽게 한 wrapper. Swift/Kotlin으로 모듈을 만들고 자동 JS 바인딩을 받는다.
# Expo SDK 53 신규 앱
npx create-expo-app@latest my-app --template default

cd my-app

# 로컬 개발
npx expo start

# 클라우드 빌드
npx eas build --platform ios --profile development
npx eas build --platform android --profile production

# OTA 업데이트 푸시
npx eas update --branch production --message "fix: button text typo"

Expo Router는 RN 라우팅을 근본적으로 바꿨다.

# 파일 구조
app/
  _layout.tsx       # 루트 레이아웃 (탭 또는 스택)
  index.tsx         # 홈 (/)
  login.tsx         # 로그인 (/login)
  (tabs)/
    _layout.tsx     # 탭 레이아웃
    index.tsx       # 탭 홈
    profile.tsx     # 탭 프로필 (/profile)
  product/
    [id].tsx        # 동적 라우트 (/product/123)

React Navigation을 손으로 구성하던 옛 RN 패턴과 비교하면, Expo Router는 Next.js 출신 개발자에게 "그대로"의 학습 곡선이다.


6장 · Capacitor 7 + Ionic — WebView 진영의 진화

Capacitor는 Ionic 팀이 만든 WebView 기반 크로스플랫폼 런타임이다. 옛 Cordova의 후계자이고, 2025년의 Capacitor 7은 의미 있는 진화를 했다.

  • 웹 UI(React, Vue, Angular, Svelte 자유 선택)를 네이티브 컨테이너에 띄운다.
  • 네이티브 기능(카메라, GPS, 푸시, 파일)은 플러그인 시스템으로 접근.
  • 100% 네이티브 빌드 산출물(.ipa, .apk).
  • PWA를 그대로 모바일 앱으로 포팅 가능.
// Capacitor: 카메라 플러그인 사용
import { Camera, CameraResultType } from '@capacitor/camera'

async function takePhoto() {
  const photo = await Camera.getPhoto({
    quality: 90,
    allowEditing: false,
    resultType: CameraResultType.Uri,
  })
  // photo.webPath 를 <img src=...> 에 바로 쓸 수 있다
  return photo.webPath
}

Capacitor 7의 핵심 변화: iOS WKWebView, Android WebView 둘 다 최신 엔진으로 통일 됐다. 결과적으로 모던 CSS(Container Queries, View Transitions API)와 WebGPU 일부 기능이 동작한다.

언제 Capacitor가 맞나: 콘텐츠 중심 앱, 사내 도구, 빠른 출시가 우선인 MVP, 웹팀의 기존 코드 재사용. 언제 안 맞나: 헤비 애니메이션, 게임, 60fps 스크롤이 필수인 피드.


7장 · Tauri 2 Mobile — Rust로 모바일

2024년 10월의 Tauri 2.0은 가장 큰 사건 중 하나다. 그동안 Tauri는 데스크톱 전용(Rust 백엔드 + WebView 프론트)이었지만, 2.0부터 iOS와 Android 모바일을 정식 지원한다.

  • 백엔드는 Rust로 짠다. iOS는 정적 라이브러리, Android는 JNI로 빌드된다.
  • 프론트는 시스템 WebView(WKWebView, Android WebView). 웹 기술(React/Vue/Svelte) 자유.
  • IPC(Inter-Process Communication)는 명령(command)과 이벤트로 표준화.
  • 바이너리 크기는 React Native·Flutter보다 작다(<10MB 가능).
# Tauri 2 모바일 프로젝트 초기화
npm create tauri-app@latest my-mobile-app
cd my-mobile-app

# Android 타깃 추가
npm run tauri android init
npm run tauri android dev

# iOS 타깃 추가
npm run tauri ios init
npm run tauri ios dev
# tauri.conf.json (요약)
app:
  product-name: my-mobile-app
  identifier: com.example.app
  windows:
    - title: my-mobile-app
      width: 800
      height: 600
bundle:
  active: true
  targets: all
  android:
    minSdkVersion: 24
  iOS:
    minimumSystemVersion: '14.0'

Tauri 2 모바일은 아직 RN/Flutter 만큼 성숙하지 않다. Hot reload는 있지만 plugin 생태계는 한참 작고, App Store 심사 노하우도 적다. 하지만 "Rust 백엔드 + 웹 프론트 + 매우 작은 바이너리"라는 조합은 시스템 프로그래머에게 매력적이다.


8장 · Kotlin Multiplatform — 비즈니스 로직 공유의 정석

JetBrains의 Kotlin Multiplatform(KMP, 옛 KMM)은 다른 길을 간다. UI는 각 플랫폼 네이티브(SwiftUI on iOS, Compose on Android), 비즈니스 로직과 데이터 레이어만 공유 한다.

  • commonMain: 공유 코드(Kotlin).
  • androidMain: Android 전용.
  • iosMain: iOS 전용. Kotlin/Native로 iOS 프레임워크(.framework)로 빌드되고, Swift에서 임포트한다.
  • expect/actual 키워드로 플랫폼별 구현을 분기한다.
// shared/src/commonMain/kotlin/Repository.kt
class UserRepository(private val api: UserApi) {
    suspend fun fetchUser(id: String): User = api.getUser(id)
}

expect class PlatformLogger() {
    fun log(message: String)
}
// shared/src/androidMain/kotlin/PlatformLogger.android.kt
actual class PlatformLogger actual constructor() {
    actual fun log(message: String) {
        android.util.Log.d("KMP", message)
    }
}
// iosApp/iosApp/ContentView.swift
import shared

struct ContentView: View {
    let repo = UserRepository(api: UserApi())

    var body: some View {
        Text("Hello, KMP!")
            .task {
                let user = try? await repo.fetchUser(id: "1")
            }
    }
}

KMP의 큰 장점: 네이티브 UI를 그대로 쓴다. iOS는 SwiftUI, Android는 Compose. 두 디자인 가이드를 완벽히 따른다. 단점은 UI를 두 번 짜야 한다는 것.

토스·당근마켓·라인·메르카리가 KMP를 일부 채택했고, 2025-2026년 카카오와 라쿠텐도 검토를 시작했다는 발표가 있었다.


9장 · Compose Multiplatform — 공유 UI까지 가는 KMP의 확장

JetBrains는 KMP의 한계(UI는 따로 짜야 함)를 해결하기 위해 Compose Multiplatform을 만들었다. Android의 Jetpack Compose를 iOS·데스크톱·웹에도 가져온다.

  • 같은 @Composable 함수가 안드로이드·iOS·데스크톱·웹에서 돈다.
  • iOS는 Kotlin/Native + Skia 렌더러로 돈다(Flutter와 비슷).
  • 안드로이드는 그대로 Jetpack Compose이고, Material 3 디자인 시스템 호환.

Compose Multiplatform 1.7(2025년 출시)부터 iOS가 정식 안정 단계(stable)에 진입했다. JetBrains 데모와 카카오·토스의 PoC 결과 60fps가 일반적으로 가능하다.

// shared/src/commonMain/kotlin/App.kt
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun App() {
    var count by remember { mutableStateOf(0) }

    MaterialTheme {
        Column(modifier = Modifier.padding(16.dp)) {
            Text("Compose Multiplatform on iOS/Android")
            Button(onClick = { count++ }) {
                Text("Clicked $count times")
            }
        }
    }
}

장점: 진짜 한 번 짜기. 단점: iOS 네이티브 룩앤필을 정확히 따르려면 추가 노력 필요. Flutter와 비슷하지만 Kotlin이라는 점이 차이.


10장 · .NET MAUI — Xamarin의 후계자

Microsoft의 .NET MAUI(Multi-platform App UI)는 Xamarin Forms의 후계자다. .NET 9 기반에서 iOS·Android·macOS·Windows를 모두 타깃으로 한다.

  • 단일 프로젝트로 멀티 플랫폼.
  • C# + XAML로 UI를 짠다.
  • 옛 Xamarin Native(Xamarin.iOS, Xamarin.Android)는 2024년 5월 EOL.
  • Hot Reload, .NET MAUI Blazor 하이브리드(WebView + .NET)도 지원.
# .NET MAUI 신규 프로젝트
dotnet new maui -n MyApp
cd MyApp

# iOS 빌드 (macOS에서)
dotnet build -t:Run -f net9.0-ios

# Android 빌드
dotnet build -t:Run -f net9.0-android

.NET MAUI는 엔터프라이즈 .NET 팀이 모바일에 진출할 때 자연스러운 선택이다. 일본의 SI 시장에서 점유율이 있고, 한국의 일부 금융권에서도 채택 사례가 있다. 단점은 모바일 커뮤니티 규모가 RN/Flutter보다 작다는 점.


11장 · NativeScript — Vue·Angular와 함께

NativeScript는 Cordova/Capacitor와 RN 사이의 위치다. WebView를 안 쓰지만, JS로 네이티브 뷰를 직접 조작한다. RN이 JSI로 가는 동안 NativeScript는 자체 V8 통합으로 비슷한 길을 갔다.

  • Vue, Angular, Svelte와 통합이 잘 된다(특히 Vue/Angular 팀에 인기).
  • iOS는 Objective-C++, Android는 Java를 메타데이터로 노출해 JS에서 직접 호출.
  • 옛 NativeScript Core는 유지보수 모드, @nativescript/core 8.x가 현행.
  • 커뮤니티 규모는 RN·Flutter보다 작지만, Vue 기반 모바일에서는 유효한 선택.

NativeScript는 2026년에 niche 포지션이지만, Vue·Angular 코드베이스를 모바일로 가져갈 때 학습 비용이 가장 낮다는 강점이 있다.


12장 · ByteDance Lynx — 2025년의 새 얼굴

2025년 3월, ByteDance가 사내 프레임워크 Lynx를 오픈소스로 공개했다. TikTok·Douyin의 라이브 커머스 UI, 미니앱 컨테이너, 댓글 화면 등이 Lynx로 돌아간다.

Lynx의 설계 철학:

  • 렌더링 엔진 분리: JS 스레드와 렌더링 스레드를 분리. JS가 막혀도 UI는 60fps 유지.
  • CSS-in-Style: React Native의 StyleSheet보다 진짜 CSS에 가까운 문법. Flexbox·Grid·Animation 풀 지원.
  • Multi-Threading: JS 코드가 메인 스레드를 막지 않도록 처음부터 설계.
  • Web과 호환: 동일 코드가 React DOM과 Lynx에서 모두 돌도록 추상화.
// Lynx 컴포넌트 (TypeScript + JSX)
import { Component } from '@lynx-js/react'

class Counter extends Component {
  state = { count: 0 }

  render() {
    return (
      <view className="container">
        <text className="title">Lynx Counter</text>
        <text className="count">Count: {this.state.count}</text>
        <view bindtap={() => this.setState({ count: this.state.count + 1 })}>
          <text>Tap to increment</text>
        </view>
      </view>
    )
  }
}

Lynx는 2026년 시점에서 RN/Flutter만큼 성숙하지는 않지만, ByteDance 같은 거대 사용자 + 오픈소스라는 점이 매력이다. 한국·일본에서는 아직 채택 사례가 적지만, 라이브 커머스를 운영하는 기업이 관심을 보이고 있다.


13장 · 렌더링 모델 비교

프레임워크렌더링 방식그래픽 API첫 프레임 jank60fps 난이도
React Native (New Arch)네이티브 뷰 + FabricUIKit / Android Views낮음보통
Flutter (Impeller)자체 렌더러Metal / Vulkan매우 낮음쉬움
CapacitorWebViewWebKit / Blink보통보통
Tauri 2 MobileWebViewWebKit / Blink보통보통
Compose MultiplatformSkiaMetal / OpenGL낮음쉬움
.NET MAUI네이티브 뷰UIKit / Android Views보통보통
NativeScript네이티브 뷰UIKit / Android Views낮음보통
Lynx자체 렌더러 + 스레드 분리Metal / OpenGL낮음쉬움
KMP (UI 따로)100% 네이티브UIKit / Compose가장 낮음가장 쉬움

자체 렌더러(Flutter, Lynx, Compose MP)는 60fps 유지가 가장 쉽다. WebView 진영(Capacitor, Tauri)은 콘텐츠 중심 앱에 적합. 네이티브 뷰 진영(RN, MAUI, NativeScript)은 OS UI 가이드를 가장 잘 따른다.


14장 · 번들 크기·바이너리 크기 비교

같은 "Hello World + 카운터 + 네트워크 요청" 앱을 빌드했을 때 대략의 크기(2026년 기준, iOS Release):

프레임워크iOS .ipaAndroid .apk비고
React Native (Hermes)~10MB~7MBHermes 바이트코드 포함
Flutter (Impeller, AOT)~15MB~9MBDart 런타임 + 아이콘 폰트
Capacitor~5MB~3MBWebView 자체는 OS 제공
Tauri 2 Mobile~4MB~3MBRust 정적 링킹
KMP (네이티브 UI)~3MB~2MB네이티브가 기본
Compose Multiplatform~12MB~5MBiOS는 Skia 포함
.NET MAUI~25MB~15MB.NET 런타임 큼
NativeScript~10MB~8MBJS 엔진 포함
Lynx~8MB~6MB자체 렌더러

KMP(네이티브 UI)와 Capacitor/Tauri(WebView)가 가장 작다. .NET MAUI가 가장 크다.


15장 · 네이티브 모듈 브릿지 — 어떻게 네이티브에 접근하나

각 프레임워크가 네이티브 기능에 접근하는 방식.

프레임워크메커니즘작성 언어타입 안전성
React Native (TurboModules)JSI HostObjectObj-C++ / Java / Kotlin / Swiftcodegen으로 강함
FlutterPlatform Channels (MethodChannel)Swift / Kotlin직렬화 기반, 수동
CapacitorCapacitor PluginSwift / Java데코레이터 기반, 보통
Tauri 2Command + IPCRustSerde 기반 강함
KMP / Compose MPexpect/actualKotlin / Swift interopKotlin 타입 그대로
.NET MAUIDependencyService / HandlerC#C# 타입 그대로
NativeScriptMetadata + ReflectionJS + Obj-C/Java 메타데이터런타임
LynxNative ModuleSwift / KotlinTypeScript codegen
// React Native TurboModule (iOS) - Swift 부분
@objc(NativeMathModule)
class NativeMathModule: NSObject {
  @objc func add(_ a: Double, b: Double) -> NSNumber {
    return NSNumber(value: a + b)
  }
}
// Flutter MethodChannel (Android Kotlin)
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.math"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                if (call.method == "add") {
                    val a = call.argument<Int>("a") ?: 0
                    val b = call.argument<Int>("b") ?: 0
                    result.success(a + b)
                } else {
                    result.notImplemented()
                }
            }
    }
}

타입 안전성은 TurboModules와 Tauri Commands가 가장 강하고, NativeScript는 가장 약하다(런타임 메타데이터에 의존).


16장 · 핫 리로드 · 개발자 경험

프레임워크Hot ReloadHot RestartDevTools디버거
React NativeFast Refresh있음React DevToolsChrome / Flipper / Reactotron
Flutter매우 빠름있음Flutter DevToolsDart DevTools
Capacitor웹과 동일있음브라우저 DevToolsChrome / Safari
Tauri 2 Mobile빠름있음웹 + Rust 모두웹 DevTools + lldb
KMP일반 IDE있음Android Studio / Xcode양쪽 디버거
Compose Multiplatform빠름있음Compose PreviewIntelliJ / Xcode
.NET MAUIXAML Hot Reload있음Visual StudioVS / Rider
Lynx빠름있음Lynx DevToolsChrome 기반

Flutter의 Hot Reload는 여전히 업계 최고 수준이다. 상태 보존 + 위젯 트리 재빌드가 <500ms 안에 끝난다. RN Fast Refresh도 New Architecture에서 한 단계 빨라졌다.


17장 · 성능 벤치마크 — 60fps 유지의 비용

2026년 기준 일반적 벤치마크(중급 Android 디바이스, Pixel 6a 기준).

프레임워크콜드 스타트스크롤 60fps메모리 (대시보드)배터리 (1시간 사용)
React Native (New Arch + Hermes)~250ms가능~120MB~7%
Flutter (Impeller, AOT)~150ms매우 쉬움~100MB~6%
Capacitor~400ms어려움~150MB~9%
Tauri 2 Mobile~300ms어려움~110MB~8%
KMP + 네이티브 UI~120ms가장 쉬움~80MB~5%
Compose Multiplatform~200ms쉬움~110MB~6%
.NET MAUI~500ms보통~180MB~10%
Lynx~200ms매우 쉬움 (스레드 분리)~95MB~6%

네이티브에 가까운 성능은 KMP가 압도적이고, 자체 렌더러 진영(Flutter, Lynx, Compose MP)이 그 뒤를 잇는다. WebView 진영은 무거운 인터랙션에서 불리하다.


18장 · 한국 사례 — 토스의 RN→Native 마이그레이션, 카카오톡의 RN 채택

토스(Toss) 는 2020-2022년에 RN을 적극 사용했고, 일부 화면(이체, 카드 등)을 RN으로 짰다. 2023-2024년 토스의 발표에 따르면 일부 핵심 화면은 RN에서 네이티브로 재마이그레이션했다. 이유: 60fps 유지의 어려움 + 결제 화면의 보안 요구 + 네이티브만 가능한 위젯·딥링크. 다만 토스 증권 일부와 사내 도구는 여전히 RN을 쓴다.

카카오톡(KakaoTalk) 은 메시지 화면을 네이티브로 유지하지만, 카카오톡 채널·쇼핑·페이의 일부 모듈은 RN 또는 WebView로 만들어진다. 카카오엔터프라이즈는 KMP 도입 PoC를 발표했다(2024년).

당근마켓(Karrot) 은 RN을 일찍 도입했고, 2024년 발표에서 RN New Architecture 적용 후 스크롤 성능이 30% 향상됐다고 했다.

네이버 라인(LINE) 의 일본 본사는 메신저를 네이티브로 유지하지만, LINE 만화(Manga)LINE 뮤직(Music) 의 일부 화면은 Flutter로 작성된다.


19장 · 일본 사례 — 메르카리, 라쿠텐, ZOZO, Mercari Flutter

메르카리(Mercari) 는 2018년 Flutter PoC 발표 이후 Flutter를 일부 화면에 도입했고, 2022년부터 새로운 출품(listing) 화면을 Flutter로 마이그레이션했다. 2024년 발표에서 출품 플로우의 약 70%가 Flutter라고 했다.

라쿠텐(Rakuten) 은 거대한 슈퍼앱 생태계를 가지고 있고, 일부 앱(라쿠텐 키오스크, 라쿠텐 페이의 일부 화면)에 Flutter를 채택했다. 단, 라쿠텐 본 앱은 네이티브를 유지한다.

ZOZO(ZOZOTOWN) 는 2023년 ZOZOFIT(피팅 슈트) 앱을 Flutter로 만들어 출시했다. 카메라 + 3D 모델링을 다루는 앱이지만, UI 부분은 Flutter, 코어는 네이티브 모듈로 분리했다.

라인 만화(LINE Manga, 일본) 는 일부 화면이 Flutter로 작성되어 있고, 콘텐츠 뷰어 자체는 네이티브를 쓴다. CyberAgent도 일부 자회사 앱에서 Flutter를 채택했다.

일본은 한국보다 Flutter 채택률이 높은 편이고, 메르카리의 영향으로 Flutter Tokyo 커뮤니티가 활발하다.


20장 · OTA 업데이트와 App Store 정책

iOS App Store와 Android Play Store는 "네이티브 코드를 OTA로 바꾸는 것"을 금지한다. 하지만 JS 번들과 같은 인터프리트 콘텐츠는 허용된다. 그래서 RN·Capacitor·Tauri·Lynx는 OTA 업데이트가 가능하다.

  • Expo EAS Update: RN에서 가장 성숙. branch와 channel로 카나리 배포.
  • CodePush (Microsoft, 2024 EOL): 운영 종료, EAS로 마이그레이션 권장.
  • Capacitor Live Updates (Ionic): 유료 서비스로 OTA 제공.
  • 자체 구현: S3 + 버전 매니페스트로 직접 만들 수 있다.

OTA의 함정은 App Store 약관이다. 핵심 기능 변경, 결제 플로우 변경, 새 카테고리 추가는 정식 심사가 필요하다. OTA는 "버그 수정·문구 변경·작은 UI 조정" 정도로 제한해야 안전하다.


21장 · 의사결정 매트릭스 — 어떤 도구를 언제 쓰나

상황권장
네이티브 룩앤필 + 두 OS 가이드 모두 따라야 함KMP + 네이티브 UI
한 번 짜기 + 60fps + 풍부한 애니메이션Flutter
웹팀 코드 재활용 + 빠른 출시Capacitor 또는 Tauri 2
React 팀이 모바일로 가야 함React Native + Expo
기존 .NET 백엔드 팀이 모바일로.NET MAUI
Vue/Angular 팀이 모바일로NativeScript 또는 Capacitor
Kotlin 팀이 iOS도 지원해야 함Compose Multiplatform
라이브 커머스·미니앱 같은 ByteDance 패턴Lynx
Rust 백엔드를 모바일에서 재사용Tauri 2 Mobile
게임Unity, Unreal, Godot (이 글의 범위 밖)

"어떤 게 절대 정답이냐"의 답은 없다. 팀의 기존 기술 스택, 디자인 가이드 준수 정도, 시장 출시 속도, 60fps 요구가 종합적으로 결정한다.


22장 · 모노레포 전략 — Turborepo·Nx·Yarn Workspaces

크로스플랫폼 앱은 보통 웹과 한 저장소에 둔다. 2026년의 표준 패턴.

  • Turborepo + pnpm: React Native + Next.js 웹 + 패키지 공유.
  • Nx: RN, Angular, NativeScript 같이 쓰는 팀에 인기.
  • Yarn Workspaces: 단순한 패턴, 큰 빌드 매트릭스 없을 때.
  • Melos (Flutter용): Flutter 패키지 모노레포 전용 도구.
# Turborepo 패턴
my-org/
  apps/
    mobile/          # Expo RN 앱
    web/             # Next.js 웹
  packages/
    ui/              # 디자인 시스템 (RN + Web 호환)
    api-client/      # 공유 API 클라이언트
    config/          # ESLint·TS 설정
  turbo.json
  package.json

RN은 웹의 React 컴포넌트와 일부 코드를 공유할 수 있다(react-native-web). 디자인 시스템 단위에서 모노레포가 진가를 발휘한다.


23장 · CI/CD — Fastlane·Codemagic·EAS·App Center

iOS 빌드는 macOS가 필요하고, 코드 사이닝은 까다롭다. 2026년의 주요 옵션:

  • Fastlane: 가장 오래되고 성숙. 자체 호스팅도, GitHub Actions에도 통합.
  • Codemagic: Flutter 친화적 SaaS. macOS 빌드 머신 제공.
  • EAS Build (Expo): RN/Expo 특화 SaaS. iOS 인증서 자동 관리.
  • Bitrise: iOS·Android 모두 강함. 엔터프라이즈 인기.
  • GitHub Actions + macOS runner: 직접 짜기. 가장 자유롭지만 인증서 관리 직접.
  • App Center (Microsoft, 2025 EOL): 운영 종료. 다른 서비스로 마이그레이션 권장.

코드 사이닝의 함정: Apple Developer 계정($99/yr), Provisioning Profile, Push Notification 인증서, 자동 갱신 미흡 → 만료되면 빌드 실패. Match(Fastlane)로 Git에 암호화 저장하는 게 표준.


24장 · 디자인 시스템·접근성·국제화

프레임워크Material DesignCupertino (iOS look)a11yi18n
React NativeRN Paper, TamaguiiOS 기본 컴포넌트accessibilityRolei18next, FormatJS
FlutterMaterial 위젯 (기본)Cupertino 위젯 (별도)Semanticsintl 패키지
Compose MPMaterial 3 (기본)Cupertino-like 라이브러리Compose Semanticsmoko-resources
CapacitorIonic ComponentsIonic iOS theming웹 표준 ARIAi18next
Tauri 2웹 자유웹 자유웹 표준 ARIAi18next
KMP (네이티브)Android는 그대로iOS는 SwiftUI 그대로네이티브 도구Android resources / iOS Localizable.strings
.NET MAUIMaterial 일부iOS 일부AutomationProperties.resx 파일
Lynx웹 호환 컴포넌트iOS-like 컴포넌트ARIA-likei18next

접근성은 KMP·.NET MAUI·NativeScript가 강하다(네이티브 도구 그대로 쓰니까). Capacitor·Tauri는 웹 a11y 표준을 그대로 활용한다. Flutter는 Semantics 위젯을 명시적으로 붙여야 한다.


25장 · 보안·인증·결제

모바일 앱은 보안 요구가 웹보다 까다롭다.

  • Keychain (iOS) / Keystore (Android): 토큰·비밀번호의 안전한 저장소.
  • 생체 인증: Face ID·Touch ID·BiometricPrompt. RN은 react-native-keychain + react-native-biometrics, Flutter는 local_auth.
  • 인앱 결제: Apple IAP, Google Billing. RN은 react-native-iap, Flutter는 in_app_purchase. KMP는 네이티브 코드를 직접 호출.
  • 푸시 알림: FCM (Android), APNs (iOS). Expo Notifications, Flutter Firebase Messaging.
  • 앱 무결성: iOS DeviceCheck, Android Play Integrity. 루팅·탈옥 탐지.

결제 화면을 RN으로 만든 팀이 종종 후회하는 이유는, Apple/Google이 IAP 외 결제를 까다롭게 보고, RN 화면의 보안 감사가 네이티브보다 어렵기 때문이다. 토스가 일부 화면을 네이티브로 되돌린 이유 중 하나.


26장 · 에필로그 — 2027년의 풍경

크로스플랫폼은 더 이상 "한 번 짜서 둘 다"의 단일 약속이 아니다. 2027년에 일어날 세 변화:

  1. AI 코드 생성이 두 플랫폼 코드의 비용을 줄인다. Cursor·Claude Code가 SwiftUI와 Compose를 동시에 생성하는 것이 흔해지면, "공유 코드"의 가치가 일부 침식된다. 그래도 비즈니스 로직 공유(KMP)는 여전히 매력적이다.
  2. 자체 렌더러 진영의 확산. Flutter Impeller가 표준이 되고, Lynx가 라이브 커머스에서 점유율을 키우며, Compose Multiplatform이 iOS에서 안정 단계로 정착한다.
  3. WebView 진영의 르네상스. Capacitor 7과 Tauri 2 Mobile은 시스템 WebView의 진화(WebKit 17, Android WebView 130+)와 함께 점유율을 키운다. PWA를 모바일 앱으로 포팅하는 비용이 가장 낮다.

가장 큰 교훈은 단순하다. 모든 화면을 같은 도구로 짤 필요는 없다. 토스가 결제 화면은 네이티브, 사내 도구는 RN을 쓰는 것처럼, 한 회사 안에서도 화면별로 적절한 도구를 고르는 게 2026년의 정답이다.


References