Skip to content

Split View: 크로스 플랫폼 모바일 개발 2026 — React Native New Architecture / Flutter / KMP / Tauri / Lynx 심층 비교

|

크로스 플랫폼 모바일 개발 2026 — React Native New Architecture / Flutter / KMP / Tauri / Lynx 심층 비교

프롤로그 — 2026, 다섯 강자의 시대

2018년의 모바일 크로스 플랫폼은 두 강자였다. React NativeFlutter. 그 사이를 Cordova·Ionic 같은 웹뷰 진영이 메우고, NativeScript는 변두리에 있었다.

2026년 5월, 풍경이 완전히 다르다.

  • React Native 는 0.76부터 New Architecture(Fabric + TurboModules + Hermes)가 기본이 되었다. 2026년 후반 React Native 1.0 이 예고됐다.
  • Expo 는 사실상 RN의 표준이 됐다. SDK 52, Expo Router 4, EAS Build·Update가 없으면 "RN 한다"는 말이 어색해졌다.
  • Flutter 3.27Impeller 렌더러를 모든 플랫폼에서 기본으로 켰다. Skia 시대의 잰크는 옛말이다.
  • Compose Multiplatform 1.7 + KMP 2.1 — iOS가 정식 stable이다. Jetpack Compose를 iOS에서 그대로 돌리는 시대.
  • Tauri 2 Mobile 이 beta로 진입했다. Rust + 시스템 웹뷰 조합으로 번들 30MB 이하를 노린다.
  • Lynx — ByteDance가 2025년 3월에 오픈소스로 푼 새 프레임워크. TikTok·Lark가 내부에서 쓰던 물건이다.

다섯 강자다. 그리고 그 위로 Capacitor 7, .NET MAUI, NativeScript 가 자기 자리를 지킨다.

이 글은 2026년의 모바일 크로스 플랫폼 지도를 — 네 가지(이제 다섯 가지) 모델부터 한국·일본의 실제 사용 사례까지 — 한 호흡에 정리한다.


1장 · 2026년 모바일 크로스 플랫폼 지도 — 다섯 강자

다섯 강자를 한 표에 놓고 시작한다. 숫자는 npm/pub.dev/Maven Central 다운로드와 GitHub star 기준 2026년 5월 시점이다.

프레임워크언어렌더링 모델번들 크기(빈 앱)핵심 강점
React Native + ExpoTypeScript/JSNative render(Fabric)iOS 15MB / Android 13MB웹 개발자 친화, 거대 생태계
FlutterDart자체 렌더러(Impeller)iOS 17MB / Android 14MB픽셀 단위 일관성, 60fps 일관
Compose Multiplatform + KMPKotlinSkia(Skiko)iOS 18MB / Android 9MB코드 공유 자유도(UI 또는 logic만)
Tauri 2 MobileRust + 웹 프론트시스템 WebViewiOS 8MB / Android 6MB번들 최소, 보안, Rust 백엔드
LynxTypeScript/JS듀얼 스레드 + 자체 렌더미공개(추정 12MB)TikTok급 성능, 듀얼 스레드

옆자리 후보 셋.

프레임워크언어렌더링 모델메모
Capacitor 7 (Ionic)TypeScript/JS시스템 WebViewIonic 팀, 웹 우선
.NET MAUIC#/XAMLNative render마이크로소프트 진영, 엔터프라이즈
NativeScriptTypeScript/Vue/SvelteNative render(JS 브리지)작은 커뮤니티, 살아있음

기억할 한 줄: "렌더링 모델이 곧 성격이다." 시스템 웹뷰는 빠르게 만들고, native 렌더는 일관되게 만들고, 자체 렌더러는 픽셀까지 통제한다.


2장 · 모바일 크로스 플랫폼의 네 가지 모델 (이제 다섯)

크로스 플랫폼은 결국 "네이티브 UI를 어떻게 그리느냐" 의 문제다. 다섯 가지 길.

1) WebView 모델 — Capacitor / Cordova / Tauri Mobile

iOS의 WKWebView와 Android의 WebView 위에 웹 앱을 얹는다. 카메라·블루투스·푸시 같은 OS 기능은 네이티브 플러그인이 JS 브리지로 노출한다.

  • 장점 — 웹 개발자가 그대로 모바일을 만든다. 번들 크기가 작다. 핫 업데이트가 자유롭다(스토어 우회는 별도 정책 이슈).
  • 단점 — 60fps 인터랙션이 어렵다. iOS WKWebView 메모리·키보드 이슈. App Store가 "그냥 웹뷰 래퍼"를 거절하는 경우.

2) Native Bridge 모델 — React Native (구 Architecture) / NativeScript

JS 엔진이 따로 돌고, 네이티브 UI(UIView·View)는 별도로 산다. 둘 사이를 JSON 메시지 큐로 잇는다.

  • 장점 — UI는 진짜 네이티브 컴포넌트, 즉 OS 업데이트에 자동으로 따라간다.
  • 단점 — 브리지가 비동기 + 직렬화라 큰 리스트·애니메이션에서 잰크. New Architecture가 이 문제를 푼다.

3) Native Render 모델 — React Native New Architecture / .NET MAUI

JS는 여전히 따로 돌지만, JSI(JavaScript Interface)로 동기 호출이 가능하고, Fabric이 C++ 레이어에서 네이티브 뷰 트리를 직접 만든다.

  • 장점 — 진짜 네이티브 컴포넌트 + 동기 호출 + concurrent rendering.
  • 단점 — 마이그레이션 비용. 구 아키텍처용 라이브러리가 일부 남아있다.

4) 자체 렌더러 모델 — Flutter / Compose Multiplatform (iOS)

OS의 네이티브 UI를 쓰지 않는다. Skia/Impeller 같은 그래픽 라이브러리로 모든 픽셀을 직접 그린다. iOS 버튼·Android 버튼이 모두 Flutter가 그리는 버튼이다.

  • 장점 — 픽셀 단위 일관성. 한 코드가 모든 OS에서 똑같이 보인다.
  • 단점 — OS UI 변화(Material You 업데이트, Dynamic Type, 접근성)를 직접 따라가야 한다.

5) 듀얼 스레드 + 자체 렌더 — Lynx

ByteDance의 새 모델. JS 스레드(메인 비즈니스)와 별도 UI 스레드를 두고, 첫 화면을 동기로 그린다. RN의 Fabric과 유사하지만 더 공격적으로 메인 스레드를 보호한다.

기억할 한 줄: "WebView는 빠르게, Native Render는 일관되게, 자체 렌더는 픽셀까지."


3장 · React Native New Architecture — 0.76부터 기본

2024년 10월 0.76 릴리스가 분기점이었다. New Architecture 가 기본 활성화 가 되었고, 이후 모든 신규 프로젝트는 자동으로 Fabric + TurboModules + Hermes 셋업이다.

세 부품의 역할을 분리해서 본다.

Hermes — JS 엔진

페이스북이 만든 JS 엔진. RN 0.70부터 기본이었고, 2026년 현재 사실상 RN의 표준 엔진이다.

  • AOT 바이트코드 — 앱 빌드 시 JS를 Hermes 바이트코드로 컴파일. 시작 속도가 빠르다.
  • 메모리 사용량이 V8/JSC보다 낮다.
  • 디버거 — Chrome DevTools가 직접 Hermes에 붙는다.

JSC(JavaScriptCore)는 호환성용으로 남아있지만 신규 권장은 Hermes다. V8은 Android에서만 옵션으로 가능하다(번들이 커진다).

JSI — JavaScript Interface

JS와 네이티브를 잇는 새 다리. 핵심은 두 줄.

  • 브리지가 아니라 C++ HostObject 다 — JS에서 보이는 객체가 사실은 C++ 메모리.
  • 동기 호출 이 가능하다 — 예전엔 모든 호출이 비동기 JSON 메시지였다.
// JSI 위에서 동기로 도는 호출 (TurboModule)
import { NativeModules } from 'react-native'
const { CryptoModule } = NativeModules

// 예전: 비동기였다
// const hash = await CryptoModule.sha256(input)

// 지금(TurboModule + JSI): 동기 가능
const hash = CryptoModule.sha256Sync(input)

TurboModules — 네이티브 모듈 인터페이스

CodegenSchema로 TypeScript 타입에서 C++/Java/Obj-C 인터페이스를 자동 생성한다. 예전 NativeModules의 런타임 dynamic dispatch가 컴파일 타임 type-safe로 바뀌었다.

// specs/NativeCrypto.ts
import type { TurboModule } from 'react-native'
import { TurboModuleRegistry } from 'react-native'

export interface Spec extends TurboModule {
  sha256(input: string): string
  randomBytes(length: number): string
}

export default TurboModuleRegistry.getEnforcing\<Spec\>('Crypto')

이 한 파일에서 Android(Java/Kotlin)·iOS(Obj-C/Swift) 인터페이스 코드가 자동 생성된다.

Fabric — 새 UI 매니저

C++ 레이어에서 React 트리를 받아 네이티브 뷰 트리를 직접 만든다.

  • Concurrent rendering — React 18의 Suspense·startTransition이 RN에서 제대로 돈다.
  • Shadow tree 동기화 — 레이아웃 계산이 한 트리에서 끝난다(예전엔 JS·Shadow·Native 셋이 각자 가졌다).
  • Synchronous events — 스크롤·터치가 메인 스레드에서 동기로 처리되어 잰크가 줄었다.

마이그레이션 체크리스트

# 0.76+ 신규 프로젝트
npx @react-native-community/cli@latest init MyApp  # 자동으로 New Arch

# 기존 프로젝트 마이그레이션
# 1. RN 0.76+ 로 업그레이드
npx react-native upgrade

# 2. iOS Podfile
# RCT_NEW_ARCH_ENABLED=1 npx pod-install

# 3. Android gradle.properties
# newArchEnabled=true

# 4. 호환 안 되는 라이브러리 점검
npx react-native doctor

4장 · Expo SDK 52 + Expo Router 4 — 사실상 표준

"맨 RN으로 시작한다"는 말은 2026년에는 거의 듣지 않는다. Expo 가 곧 RN의 표준 셋업 이 되었다. 이유는 셋이다.

  1. EAS Build — 로컬 Xcode 없이 클라우드 빌드. iOS 인증서·프로비저닝까지 다 관리해 준다.
  2. EAS Update — JS·이미지·소형 자산 OTA 업데이트. App Store 우회가 아니라 "버그 수정 빠르게".
  3. Expo Router 4 — 파일 기반 라우팅이 네이티브 앱에 그대로. Next.js의 app/ 디렉터리가 모바일에 온 셈.

Expo Router 4 — 파일 기반 라우팅

app/
├── _layout.tsx              # 루트 레이아웃 (Tab/Stack)
├── (tabs)/
│   ├── _layout.tsx          # 탭 레이아웃
│   ├── index.tsx            # /
│   ├── feed.tsx             # /feed
│   └── profile.tsx          # /profile
├── post/
│   └── [id].tsx             # /post/123 (동적 라우트)
├── modal.tsx                # /modal (네이티브 모달)
└── +not-found.tsx           # 404
// app/_layout.tsx
import { Stack } from 'expo-router'

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="modal" options={{ presentation: 'modal' }} />
    </Stack>
  )
}
// app/post/[id].tsx
import { useLocalSearchParams } from 'expo-router'
import { Text, View } from 'react-native'

export default function PostScreen() {
  const { id } = useLocalSearchParams\<{ id: string }\>()
  return (
    <View>
      <Text>Post {id}</Text>
    </View>
  )
}

핵심은 두 가지다.

  • 타입세이프 링크expo-router가 라우트 타입을 자동 생성한다. 잘못된 라우트는 컴파일 타임에 에러.
  • 딥링크가 공짜/post/123 URL이 그대로 앱 안에서 동작한다. 웹·iOS·Android 셋이 같은 라우트 트리를 본다.

EAS Build — 클라우드 빌드

// eas.json
{
  "cli": { "version": ">= 13.0.0" },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal",
      "ios": { "simulator": false }
    },
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {}
  }
}
eas build --platform ios --profile production
eas submit --platform ios --latest

이 두 줄이면 App Store까지 간다. Xcode는 한 번도 열지 않는다.

EAS Update — OTA

# 코드만 바뀐 작은 변경
eas update --branch production --message "Fix login crash"

네이티브 모듈을 안 건드린 변경이라면 스토어 리뷰 없이 사용자에게 도달한다. App Store 가이드라인을 지키는 한 합법이다(주요 기능 변경·UI 전면 개편은 정식 빌드 권장).


5장 · Flutter 3.27 + Impeller — 자체 렌더러 전략

Flutter는 처음부터 길을 달리 갔다. OS의 네이티브 UI를 쓰지 않는다. Skia(이제는 Impeller)로 모든 픽셀을 직접 그린다.

Impeller — Skia를 대체한 새 렌더러

2024년까지는 Skia + GPU shader 컴파일이라는 두 단계 때문에 첫 프레임 잰크가 있었다. Impeller 는 그 문제를 푼 새 렌더러다.

  • 셰이더 미리 컴파일 — 빌드 시 GPU 셰이더가 다 컴파일되어 들어간다. 런타임 컴파일 잰크가 사라졌다.
  • Metal(iOS)·Vulkan(Android) 백엔드를 기본으로 쓴다. OpenGL ES는 폴백.
  • Flutter 3.27부터 iOS·Android 모두 기본.

Material You 3 + Cupertino

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: 'Flutter Demo',
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF6750A4),
        useMaterial3: true,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: const Color(0xFF6750A4),
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      home: const HomeScreen(),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Hello Flutter 3.27')),
      body: const Center(child: Text('Material You 3 + Impeller')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
    );
  }
}

useMaterial3: true + colorSchemeSeed 한 줄이면 Material You 컬러 시스템이 자동 적용된다. Light·Dark 톤맵핑·접근성 콘트라스트까지 자동.

자체 렌더러의 정체성

장단을 분명히 한다.

  • 장점 — Android·iOS·웹·데스크톱이 픽셀 단위로 동일. 디자이너의 픽셀 퍼펙트가 진짜 동작한다.
  • 단점 — OS의 UI 진화(iOS Dynamic Island 같은)에 직접 대응해야 한다. 접근성도 OS 위임이 아니라 직접 구현.

Flutter의 길은 "OS와 다른 길로 가더라도 일관성을 잡는다" 다. 게임·미디어·브랜드 강한 앱에 잘 맞고, OS 룩앤필을 그대로 따라가야 하는 앱에는 다소 어색할 수 있다.


6장 · Compose Multiplatform 1.7 / KMP 2.1 — iOS 정식 stable

2024년까지 Compose Multiplatform의 iOS는 "alpha"였다. 2025년 2분기 1.6에서 beta, 2026년 1분기 1.7에서 stable. 이게 뜻하는 바는 크다.

Jetpack Compose 로 짠 코드가 iOS에서 그대로 돈다.

KMP — 코드 공유의 자유도

Kotlin Multiplatform은 "공유 범위를 자유롭게" 가 핵심이다. 세 가지 선택.

  1. Logic만 공유 — 네트워크·DB·도메인은 KMP, UI는 SwiftUI(iOS)·Compose(Android). 가장 보수적이고 가장 많이 쓰이는 패턴.
  2. Logic + UI 일부 공유 — 공통 화면은 Compose Multiplatform, 플랫폼 특화 화면은 네이티브.
  3. Logic + UI 전부 공유 — 100% Compose Multiplatform. Flutter와 비슷한 자체 렌더(iOS는 Skiko = Skia for Kotlin).
// shared/src/commonMain/kotlin/UserRepository.kt
class UserRepository(private val api: UserApi, private val db: UserDb) {
    suspend fun getUser(id: String): User {
        return db.findById(id) ?: api.fetch(id).also { db.insert(it) }
    }
}
// shared/src/commonMain/kotlin/App.kt
@Composable
fun App() {
    MaterialTheme {
        var name by remember { mutableStateOf("World") }
        Column {
            TextField(value = name, onValueChange = { name = it })
            Text("Hello, $name!")
        }
    }
}
// iOS 앱에서 호출
import shared
import SwiftUI

struct ContentView: View {
    var body: some View {
        ComposeView()  // Compose UI를 SwiftUI에 임베드
    }
}

KMP 2.1의 새로움

  • K2 컴파일러 가 기본 — 컴파일 속도 약 2배.
  • expect/actual 가 더 안정화되어 플랫폼 특화 구현이 깔끔하다.
  • Native target 이 Apple Silicon 빌드를 더 빠르게.

Compose Multiplatform iOS — 어디까지 왔나

  • iOS Stable — 프로덕션 권장.
  • Skiko 렌더링 — Skia 기반(Flutter의 Skia와 같은 라이브러리, 다른 통합).
  • 접근성 — VoiceOver 지원이 1.7에서 크게 좋아졌다(아직 100% SwiftUI는 아니다).
  • 텍스트 입력 — iOS 키보드·IME가 안정화됐지만 한국어 IME에서 가끔 카더라가 있다.

기억할 한 줄: "KMP는 logic부터 시작해서 점진적으로 UI까지 올라가는 길을 준다."


7장 · Tauri 2 Mobile — Rust + 시스템 웹뷰의 새 시도

Tauri는 데스크톱(Windows/macOS/Linux)에서 Electron의 대안으로 자리를 잡았다. 번들 30MB 이하, 메모리 1/5 가 셀링 포인트였다. 2024~2025년에 Mobile 이 alpha→beta로 들어왔다.

구조 — Rust core + 시스템 웹뷰

  • iOS — WKWebView 위에 웹 프론트(React/Vue/Svelte/Solid 등).
  • Android — WebView(Chromium) 위에 같은 프론트.
  • Rust core — 네이티브 기능을 Rust로 작성하고 IPC로 노출.
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
// 프론트(React) 쪽
import { invoke } from '@tauri-apps/api/core'

const greeting = await invoke\<string\>('greet', { name: 'YJ' })

Tauri 2 Mobile의 강점·약점

  • 강점 — 번들 6-8MB(Android), 보안(자동 CSP·권한 manifest), Rust 백엔드(빠른 IO·암호화·DB 접근).
  • 약점 — UI 성능은 결국 시스템 웹뷰. 60fps 게임·복잡한 애니메이션엔 부적합. iOS 17 이전 호환성 일부 이슈.

누가 쓰는가

2026년 현재 Tauri Mobile은 prosumer 도구 — 보안 키 관리, 로컬 노트 앱, 개발자 유틸 — 에서 채택이 늘고 있다. TikTok급 소비자 앱은 아직 흔치 않다.


8장 · Capacitor 7 vs Cordova — 웹 우선의 현재

웹 우선 모바일의 두 라이벌이었다. Cordova는 2024년 메이저 업데이트 사실상 정지, Apache Cordova 프로젝트가 retire 트랙으로 들어갔다. 웹 우선의 자리는 사실상 Capacitor 7 (Ionic 팀이 만든) 이 차지했다.

Capacitor 7 핵심

  • iOS WKWebView · Android Chromium WebView 위에 웹 앱.
  • Capacitor Plugins — 카메라·블루투스·푸시·파일 등 네이티브 기능을 JS API로.
  • Ionic Framework 가 위에 얹어지는 UI 키트(필수는 아니다, React/Vue/Angular 어떤 거든 가능).
// Capacitor 카메라 사용
import { Camera, CameraResultType } from '@capacitor/camera'

const takePhoto = async () => {
  const photo = await Camera.getPhoto({
    quality: 90,
    allowEditing: false,
    resultType: CameraResultType.Uri,
  })
  return photo.webPath
}
# 기본 셋업
npm install @capacitor/core @capacitor/cli
npx cap init
npx cap add ios
npx cap add android
npm run build
npx cap copy
npx cap open ios

누가 쓰는가

  • PWA를 빠르게 앱화 — 기존 React/Vue 앱이 있고 1-2주 만에 스토어 진입이 필요할 때.
  • 엔터프라이즈 라인 오브 비즈니스 앱 — 사내용 도구. 성능 요구가 낮고 빠른 배포가 중요할 때.
  • 하이브리드 e-commerce — 일부 화면만 네이티브(체크아웃), 나머지는 웹.

App Store가 "그냥 웹뷰 래퍼"를 거절하는 사례가 늘었기 때문에, Capacitor를 쓸 때는 "하이브리드 가치" — 네이티브 기능 적극 사용, 오프라인 동작, 앱스러운 인터랙션 — 를 보여야 한다.


9장 · Lynx (ByteDance) — TikTok 내부 프레임워크의 오픈소스

2025년 3월, ByteDance가 Lynx 를 오픈소스로 풀었다. 사내에서 TikTok·Lark·Douyin 같은 거대 앱이 쓰던 크로스 플랫폼 프레임워크다. 의미는 크다.

왜 새 프레임워크인가

RN과 Flutter가 있는데 왜? ByteDance의 공식 설명을 거칠게 옮기면.

  • 메인 스레드 보호 — TikTok 같은 무한 스크롤·짧은 영상 앱에서 첫 프레임 동기 렌더가 핵심이다. RN의 Fabric도 좋지만 더 공격적으로 메인 스레드를 비우고 싶었다.
  • 듀얼 스레드 모델 — Main thread(UI 동기 렌더)와 Background thread(JS 로직)를 분리. 첫 프레임이 동기로 그려진다.
  • PrimJS — Lynx 전용 JS 엔진(QuickJS 기반 포크). Hermes와 비슷한 AOT 바이트코드 접근.

Lynx 한 줄 코드

import { View, Text, Image } from '@lynx-js/react'

export default function App() {
  return (
    <View style={{ padding: 20 }}>
      <Text style={{ fontSize: 24 }}>Hello Lynx</Text>
      <Image src="https://example.com/cat.jpg" style={{ width: 100, height: 100 }} />
    </View>
  )
}

표면적으로는 RN과 거의 비슷한 JSX·컴포넌트 모델. 차이는 내부에 있다.

무엇이 다른가

  • 첫 프레임 동기\<List\>가 처음 그릴 때 메인 스레드에서 동기로 레이아웃·페인트.
  • Atomic CSS — Tailwind 비슷한 atomic CSS가 1급 시민. 빌드 시 사전 처리.
  • Rust 코어 — 일부 critical path가 Rust로 다시 짜여졌다.

누구를 위한 도구인가

ByteDance가 자기 앱(TikTok급)을 위해 만들었다. 그 말은 거대 트래픽 + 무한 스크롤 + 짧은 영상 에 특화돼 있다는 뜻이다. 일반 SaaS·이커머스·생산성 앱은 RN/Flutter가 여전히 안전한 선택이다.

오픈소스화의 진짜 의미는 "RN/Flutter가 못 따라가는 케이스가 있다" 는 공개 인정과, TikTok급 노하우의 외부 유출이다. 2026년 후반~2027년에 누가 따라가는지가 관전 포인트.


10장 · .NET MAUI / NativeScript — 그 외 옵션

다섯 강자 외에 두 옵션이 자기 자리를 지킨다.

.NET MAUI — 마이크로소프트의 답

Xamarin.Forms의 후계. C# + XAML로 iOS·Android·Windows·macOS 한 코드로.

<!-- MainPage.xaml -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
  <VerticalStackLayout>
    <Label Text="Hello, MAUI!" FontSize="32" />
    <Button x:Name="CounterBtn" Text="Click me" Clicked="OnCounterClicked" />
  </VerticalStackLayout>
</ContentPage>
  • 강점 — Visual Studio 통합, .NET 진영 라이브러리 그대로, 엔터프라이즈 SSO·Active Directory가 한 줄.
  • 약점 — 모바일 first 디자인이 아니고 Xamarin 유산이 남아있다. 커뮤니티 활성도가 RN/Flutter보다 낮다.

NativeScript — 살아있다

Telerik 시절부터 살아남았다. TypeScript/Vue/Svelte/Angular로 진짜 네이티브 UI(UIView·View) 를 직접 다룬다.

  • 강점 — JS에서 iOS·Android API를 거의 그대로 호출(브리지 코드 없이).
  • 약점 — 커뮤니티가 작다. RN의 New Architecture 이후 차별점이 흐려졌다.

2026년 5월 현재 NativeScript는 "RN 이전 시대의 향수" 가 더 큰 이유로 쓰인다. 신규 프로젝트라면 RN/Flutter/KMP가 먼저 고려된다.


11장 · 어떤 프레임워크를 골라야 하나 — 의사결정 표

다섯 강자 + 두 옵션을 팀·제품·디자인·번들사이즈로 줄세운다.

팀 기준

팀 배경1순위2순위메모
웹(React/TS)React Native + ExpoCapacitor 7RN 학습 곡선이 가장 낮다
웹(Vue/Svelte)Capacitor 7Tauri 2 MobileRN의 React 의존이 거슬리면
Kotlin/AndroidKMP + Compose MultiplatformFlutteriOS 점진 도입 가능
iOS 위주KMP (logic만)React NativeSwiftUI는 그대로 유지
Dart/모바일 firstFlutterCompose Multiplatform픽셀 일관성 우선
C#/.NET.NET MAUIReact Native엔터프라이즈

제품 기준

제품 종류추천이유
콘텐츠·피드 앱(TikTok급)Lynx 또는 RN메인 스레드 보호
게임·미디어 인터랙티브Flutter픽셀 단위 60fps
핀테크·은행RN (Expo) 또는 KMP큰 생태계, 보안 라이브러리
이커머스RN (Expo)빠른 출시, 광고 SDK 호환
사내 LOB 앱Capacitor 7빠른 배포, 낮은 비용
prosumer 도구Tauri 2 Mobile번들 작고 보안

디자인 기준

디자인 방향추천
OS 표준 룩앤필 강조RN, KMP(SwiftUI/Compose 따로)
브랜드 픽셀 퍼펙트Flutter, Compose Multiplatform
웹 디자인을 그대로Capacitor, Tauri Mobile

번들 사이즈

프레임워크iOS 빈 앱Android 빈 앱
Tauri 2 Mobile약 8MB약 6MB
Capacitor 7약 10MB약 8MB
KMP(logic 공유)약 12MB약 7MB
React Native + Expo약 15MB약 13MB
Flutter약 17MB약 14MB
Compose Multiplatform약 18MB약 9MB

번들 사이즈는 빈 앱 기준이다. 실제 앱은 이미지·폰트·라이브러리로 두세 배 커진다. 100MB 이상이면 App Store cellular download 제한에 걸려 4G/5G에서 자동 다운로드가 안 된다.


12장 · 한국·일본 모바일 생태계 — 실제로 뭘 쓰나

이론 표는 의사결정의 출발선이고, 현실은 다르다. 한국·일본의 큰 회사들이 2026년 5월 시점에 실제 뭘 쓰는지 정리한다(공개된 채용공고·기술블로그·컨퍼런스 발표 기준).

한국

  • 카카오 — Android는 Kotlin + Jetpack Compose, iOS는 Swift + SwiftUI. 일부 사내 도구·신규 서비스에 KMP(logic 공유) 도입 사례가 늘고 있다. RN은 사내 도구·이벤트성 미니앱.
  • 네이버 — 같은 방향. 핵심 앱은 네이티브(Swift/Kotlin), 검증 단계 서비스에 RN/Flutter 채용공고가 나온다.
  • 쿠팡 — RN 채택이 가장 적극적. 일부 검색·리스트 화면이 RN으로 알려져 있다. Hermes 위에서 동작.
  • 토스 — iOS Swift + Android Kotlin이 메인. 일부 사내·운영 도구가 RN.
  • 당근(당근마켓) — Flutter 도입이 가장 눈에 띈다. 일부 서비스(중고 + 동네생활)에 Flutter 사용.
  • 배달의민족(우아한형제들) — 네이티브 위주. 일부 신규 실험에 Flutter.

일본

  • 메루카리(Mercari) — Android에서 KMP 도입 사례를 컨퍼런스에서 여러 번 공유. iOS는 Swift, Android는 Kotlin이 메인, 공유 비즈니스 로직만 KMP.
  • CyberAgent — 자회사가 많아 스택이 다양. AbemaTV 는 RN/Flutter 이력 없이 네이티브. 일부 자회사는 Flutter.
  • DeNA — 게임·엔터테인먼트는 Unity/네이티브. 일반 앱은 Swift + Kotlin.
  • LINE Yahoo Japan — LINE 앱 자체는 네이티브. 일부 미니 앱·캠페인 페이지에 웹뷰.
  • PayPay — 네이티브 위주. RN/Flutter 흔적은 적다.
  • freee / SmartHR / Money Forward — SaaS 진영. 모바일 앱은 RN/Flutter 혼재, 신규 프로젝트에 Flutter 채택이 늘고 있다.

두 시장의 공통 패턴

  • 핵심 앱은 여전히 네이티브 — 슈퍼앱 격(카카오톡·LINE·페이코) 은 거의 다 Swift + Kotlin.
  • 신규·실험 서비스에 RN/Flutter — 신규 도메인, 미니 앱, 사내 도구.
  • KMP가 조용히 늘고 있다 — UI까지 가지 않고 비즈니스 로직 공유로 시작하는 패턴. 메루카리·카카오 사례가 대표.
  • Compose Multiplatform 도입은 아직 보수적 — iOS stable이 2026년 1분기라 본격 채택은 2026년 하반기~2027년에 보일 듯.

시사점

큰 회사는 "리스크 < 코드 공유 이득" 일 때만 크로스 플랫폼을 쓴다. 핵심 사용자 경험이 걸린 앱은 네이티브를 유지하고, 새로운 기능·실험·내부 도구에서 크로스 플랫폼을 검증한다. KMP의 logic-only 공유가 그 검증 진입점으로 가장 안전하다.


마무리 — 체크리스트와 안티패턴

의사결정 체크리스트

  1. 팀의 주력 언어는 무엇인가? (TS / Dart / Kotlin / Swift / C#)
  2. UI 기준이 OS 표준인가, 브랜드 픽셀 퍼펙트인가?
  3. 핵심 화면이 60fps 동영상·복잡 애니메이션인가, 폼·리스트 위주인가?
  4. 번들 크기 상한이 있는가? (App Store cellular 200MB)
  5. App Store/Play Store 리뷰 속도 vs OTA 업데이트 비중은?
  6. 기존 웹 자산이 있는가? (Capacitor/Tauri의 가치)
  7. 보안 요구는? (Tauri의 Rust 백엔드, 또는 RN의 보안 라이브러리)
  8. 5년 후 코드 유지 보수자는 누구인가?

안티패턴 10가지

  1. RN 0.76 이상에서 New Architecture 끄고 운영(불필요한 비대칭).
  2. Expo로 시작해 놓고 eject 후 후회.
  3. Flutter로 iOS 네이티브 룩앤필 흉내 내려고 시간 낭비.
  4. KMP의 UI 공유를 안정 stable 전(2025년 이전)에 프로덕션 도입한 사례 답습.
  5. Capacitor 위에 60fps 게임 애니메이션을 욱여넣음.
  6. Tauri Mobile을 TikTok급 소비자 앱에 적용 시도.
  7. Lynx를 사내 도구 같은 작은 앱에 도입(과한 도구).
  8. JS 엔진을 JSC로 고정한 채 Hermes 마이그레이션 안 함.
  9. EAS Update를 주요 UI 전면 개편에 사용해 App Store 가이드 위반 위험.
  10. .NET MAUI를 모바일 first 디자인 앱에 골라 놓고 데스크톱 패턴 강요.

다음 글 예고

다음 글 후보: React Native New Architecture 마이그레이션 실전 — 0.74→0.76 단계별 가이드, KMP logic-only 공유로 SwiftUI/Compose 둘 다 살리기, Flutter Impeller 셰이더 디버깅 — 잰크 잡는 법.

"크로스 플랫폼은 한 코드로 두 OS를 동시에 만드는 마법이 아니라, 어느 비용을 어디로 옮기느냐의 협상이다."

— 크로스 플랫폼 모바일 개발 2026, 끝.


참고 / References

Cross-Platform Mobile Development in 2026 — React Native New Architecture / Flutter / KMP / Tauri / Lynx Deep Dive

Prologue — 2026, Age of Five Contenders

In 2018, mobile cross-platform had two players: React Native and Flutter. Cordova and Ionic filled the webview niche, and NativeScript sat on the edge.

May 2026 looks completely different.

  • React Native made the New Architecture (Fabric + TurboModules + Hermes) the default starting from 0.76. React Native 1.0 is slated for late 2026.
  • Expo is effectively the standard RN setup. Saying "I do RN" without SDK 52, Expo Router 4, EAS Build, and EAS Update sounds odd.
  • Flutter 3.27 enabled the Impeller renderer by default on every platform. Skia-era jank is yesterday's problem.
  • Compose Multiplatform 1.7 + KMP 2.1 — iOS is officially stable. The era of running Jetpack Compose on iOS as-is has arrived.
  • Tauri 2 Mobile entered beta. Rust + system WebView, aiming at sub-30MB bundles.
  • Lynx — the new framework that ByteDance open-sourced in March 2025. The same one TikTok and Lark used internally.

Five contenders. Above them sit Capacitor 7, .NET MAUI, and NativeScript, all holding their lanes.

This post lays out the 2026 mobile cross-platform map in a single arc — five models, framework deep dives, and what the big Korean and Japanese companies actually ship.


1. The 2026 Cross-Platform Map — Five Contenders

Start with five frameworks on one table. Numbers are pulled from npm, pub.dev, Maven Central downloads, and GitHub stars as of May 2026.

FrameworkLanguageRenderingEmpty-app bundleCore strength
React Native + ExpoTypeScript/JSNative render (Fabric)iOS 15MB / Android 13MBWeb-developer friendly, huge ecosystem
FlutterDartOwn renderer (Impeller)iOS 17MB / Android 14MBPixel-perfect consistency, steady 60fps
Compose Multiplatform + KMPKotlinSkia (Skiko)iOS 18MB / Android 9MBFree choice of shared scope (UI or logic)
Tauri 2 MobileRust + web frontSystem WebViewiOS 8MB / Android 6MBTiny bundles, security, Rust backend
LynxTypeScript/JSDual-thread + own rendernot published (est. 12MB)TikTok-grade perf, dual threads

Three nearby contenders.

FrameworkLanguageRenderingNote
Capacitor 7 (Ionic)TypeScript/JSSystem WebViewIonic team, web-first
.NET MAUIC#/XAMLNative renderMicrosoft camp, enterprise
NativeScriptTypeScript/Vue/SvelteNative render (JS bridge)Small community, still alive

One line to remember: "Rendering model is personality." System WebViews build fast, native render stays consistent, and own-renderers control every pixel.


2. The Four Models of Mobile Cross-Platform (Now Five)

Cross-platform boils down to "how do you draw the native UI?" Five paths.

1) WebView model — Capacitor / Cordova / Tauri Mobile

Layer a web app on top of WKWebView (iOS) and the Android WebView. Camera, Bluetooth, push, etc. are surfaced by native plugins through a JS bridge.

  • Upside — web developers ship mobile directly. Tiny bundles. Free hot-updates (store policy nuance aside).
  • Downside — 60fps interactions are hard. WKWebView memory and keyboard quirks. The App Store rejects "thin webview wrappers" more often than before.

2) Native bridge model — React Native (old architecture) / NativeScript

JS runs in its own engine, native UI (UIView/View) lives separately. They communicate through a JSON message queue.

  • Upside — UI is real native components, so OS updates roll forward for free.
  • Downside — the bridge is async and serialized, so big lists and animations stutter. The New Architecture solves this.

3) Native render model — React Native New Architecture / .NET MAUI

JS still runs in its own engine, but JSI (JavaScript Interface) enables synchronous calls, and Fabric builds the native view tree directly from C++.

  • Upside — real native components plus sync calls plus concurrent rendering.
  • Downside — migration cost. Some libraries still target the old architecture.

4) Own-renderer model — Flutter / Compose Multiplatform (iOS)

Skip the native UI altogether. Draw every pixel with a graphics library like Skia / Impeller. iOS buttons and Android buttons alike are buttons Flutter draws.

  • Upside — pixel-perfect consistency. One codebase looks identical on every OS.
  • Downside — OS UI evolution (Material You updates, Dynamic Type, accessibility) is yours to track.

5) Dual-thread plus own renderer — Lynx

ByteDance's new model. A JS thread (main business logic) sits beside a separate UI thread, and the first frame is painted synchronously. Similar to RN's Fabric, only more aggressive about keeping the main thread free.

One line to remember: "WebView is fast to build, native render is consistent, own-renderer controls every pixel."


3. React Native New Architecture — Default Since 0.76

October 2024's 0.76 release was the inflection point. New Architecture became default, and every new project from that day forward ships with Fabric, TurboModules, and Hermes.

Break the three parts down.

Hermes — the JS engine

Built by Facebook. Default since RN 0.70, and effectively the standard RN engine by 2026.

  • AOT bytecode — JS is compiled to Hermes bytecode at build time. Faster startup.
  • Lower memory footprint than V8 / JSC.
  • Debugging — Chrome DevTools attaches directly to Hermes.

JSC (JavaScriptCore) is kept for compatibility, but new projects choose Hermes. V8 is available as an option on Android only, at the cost of a larger bundle.

JSI — JavaScript Interface

The new bridge between JS and native. Two key facts.

  • Not a bridge but C++ HostObject — the object you see in JS is really C++ memory.
  • Synchronous calls are possible — previously every call was an async JSON message.
// A synchronous call on JSI (TurboModule)
import { NativeModules } from 'react-native'
const { CryptoModule } = NativeModules

// Before: always async
// const hash = await CryptoModule.sha256(input)

// Today (TurboModule + JSI): sync allowed
const hash = CryptoModule.sha256Sync(input)

TurboModules — the native-module interface

CodegenSchema generates C++/Java/Obj-C interfaces from TypeScript types. The old NativeModules' runtime dynamic dispatch becomes compile-time type-safe.

// specs/NativeCrypto.ts
import type { TurboModule } from 'react-native'
import { TurboModuleRegistry } from 'react-native'

export interface Spec extends TurboModule {
  sha256(input: string): string
  randomBytes(length: number): string
}

export default TurboModuleRegistry.getEnforcing\<Spec\>('Crypto')

This one file emits Android (Java/Kotlin) and iOS (Obj-C/Swift) interface code automatically.

Fabric — the new UI manager

A C++ layer accepts the React tree and constructs the native view tree directly.

  • Concurrent rendering — React 18's Suspense and startTransition actually work in RN.
  • Shadow-tree sync — layout is computed in a single tree (previously JS, Shadow, and Native each kept their own).
  • Synchronous events — scrolls and touches run synchronously on the main thread, reducing jank.

Migration checklist

# New project on 0.76+
npx @react-native-community/cli@latest init MyApp  # New Arch on by default

# Migrating an existing project
# 1. Upgrade to RN 0.76+
npx react-native upgrade

# 2. iOS Podfile
# RCT_NEW_ARCH_ENABLED=1 npx pod-install

# 3. Android gradle.properties
# newArchEnabled=true

# 4. Audit incompatible libraries
npx react-native doctor

4. Expo SDK 52 + Expo Router 4 — The De Facto Standard

By 2026 you rarely hear "I start with bare RN." Expo is now the standard RN setup. Three reasons.

  1. EAS Build — cloud builds without local Xcode. iOS certificates and provisioning included.
  2. EAS Update — OTA updates for JS, images, and small assets. Not an App Store dodge, just "ship the bug fix faster."
  3. Expo Router 4 — file-based routing on native, the way Next.js's app/ directory feels on the web.

Expo Router 4 — file-based routing

app/
├── _layout.tsx              # root layout (Tab/Stack)
├── (tabs)/
│   ├── _layout.tsx          # tab layout
│   ├── index.tsx            # /
│   ├── feed.tsx             # /feed
│   └── profile.tsx          # /profile
├── post/
│   └── [id].tsx             # /post/123 (dynamic route)
├── modal.tsx                # /modal (native modal)
└── +not-found.tsx           # 404
// app/_layout.tsx
import { Stack } from 'expo-router'

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="modal" options={{ presentation: 'modal' }} />
    </Stack>
  )
}
// app/post/[id].tsx
import { useLocalSearchParams } from 'expo-router'
import { Text, View } from 'react-native'

export default function PostScreen() {
  const { id } = useLocalSearchParams\<{ id: string }\>()
  return (
    <View>
      <Text>Post {id}</Text>
    </View>
  )
}

Two key facts.

  • Type-safe linksexpo-router generates route types. Wrong routes fail at compile time.
  • Deep links for free — the /post/123 URL works inside the app. Web, iOS, and Android share the same route tree.

EAS Build — cloud builds

// eas.json
{
  "cli": { "version": ">= 13.0.0" },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal",
      "ios": { "simulator": false }
    },
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {}
  }
}
eas build --platform ios --profile production
eas submit --platform ios --latest

Two lines and you ship to the App Store. Xcode never opens.

EAS Update — OTA

# A small code-only change
eas update --branch production --message "Fix login crash"

If the change doesn't touch native modules, it reaches users without store review. As long as you respect App Store guidelines, this is fine (full UI revamps still warrant a real build).


5. Flutter 3.27 + Impeller — The Own-Renderer Strategy

Flutter took a different road from the start. It doesn't use the OS's native UI. Skia — now Impeller — draws every pixel.

Impeller — the renderer that replaced Skia

Through 2024 the Skia + GPU shader compile pipeline produced first-frame jank. Impeller is the new renderer that fixes it.

  • Shader precompilation — every GPU shader compiles at build time, so the runtime-compile stutter is gone.
  • Metal (iOS) / Vulkan (Android) backends by default. OpenGL ES is the fallback.
  • Default on iOS and Android as of Flutter 3.27.

Material You 3 + Cupertino

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: 'Flutter Demo',
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF6750A4),
        useMaterial3: true,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: const Color(0xFF6750A4),
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      home: const HomeScreen(),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Hello Flutter 3.27')),
      body: const Center(child: Text('Material You 3 + Impeller')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
    );
  }
}

useMaterial3: true plus colorSchemeSeed is enough to activate the full Material You color system. Light, dark, tone mapping, and accessibility contrast all wire up automatically.

The identity of the own-renderer

State the trade clearly.

  • Upside — Android, iOS, web, and desktop look identical pixel for pixel. The designer's pixel-perfect mockup actually ships.
  • Downside — UI evolution on the OS (think iOS Dynamic Island) is on you. Accessibility is something you implement, not something you delegate to the OS.

Flutter's path is "if we have to diverge from the OS to keep consistency, we will." It fits games, media, and brand-led apps. It feels awkward in apps that need to mirror OS look and feel.


6. Compose Multiplatform 1.7 / KMP 2.1 — iOS Officially Stable

Through 2024, Compose Multiplatform's iOS support was "alpha." Q2 2025 reached beta in 1.6, and Q1 2026 reached stable in 1.7. The implication is big.

The Jetpack Compose code you write runs as-is on iOS.

KMP — the freedom to choose what to share

The core idea of Kotlin Multiplatform is "share whatever you want." Three flavors.

  1. Share logic only — network, DB, domain in KMP. UI stays SwiftUI on iOS, Compose on Android. The most conservative and most adopted pattern.
  2. Logic + some UI — common screens use Compose Multiplatform, platform-specific screens stay native.
  3. Share everything — 100% Compose Multiplatform. Similar to Flutter, an own-renderer on iOS (Skiko, Skia for Kotlin).
// shared/src/commonMain/kotlin/UserRepository.kt
class UserRepository(private val api: UserApi, private val db: UserDb) {
    suspend fun getUser(id: String): User {
        return db.findById(id) ?: api.fetch(id).also { db.insert(it) }
    }
}
// shared/src/commonMain/kotlin/App.kt
@Composable
fun App() {
    MaterialTheme {
        var name by remember { mutableStateOf("World") }
        Column {
            TextField(value = name, onValueChange = { name = it })
            Text("Hello, $name!")
        }
    }
}
// Calling from the iOS app
import shared
import SwiftUI

struct ContentView: View {
    var body: some View {
        ComposeView()  // embed Compose UI inside SwiftUI
    }
}

What's new in KMP 2.1

  • K2 compiler is default — roughly 2x compile speed.
  • expect/actual stabilized, so platform-specific implementations stay clean.
  • Apple Silicon native targets build faster.

Compose Multiplatform iOS — where it sits

  • iOS Stable — production recommended.
  • Skiko rendering — Skia-based (same library as Flutter, different integration).
  • Accessibility — VoiceOver support improved significantly in 1.7 (not yet 100% on par with SwiftUI).
  • Text input — iOS keyboard / IME are stable, with occasional rough edges in Korean IME.

One line to remember: "KMP lets you start with logic and grow into UI on your own schedule."


7. Tauri 2 Mobile — Rust Plus System WebView, a New Attempt

Tauri found its footing on desktop (Windows / macOS / Linux) as an Electron alternative. Sub-30MB bundles and one-fifth the memory were the selling points. Mobile went from alpha to beta in 2024-2025.

The architecture — Rust core + system WebView

  • iOS — WKWebView hosting a web front (React / Vue / Svelte / Solid).
  • Android — WebView (Chromium) hosting the same front.
  • Rust core — write native features in Rust and expose them via IPC.
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
// On the front (React) side
import { invoke } from '@tauri-apps/api/core'

const greeting = await invoke\<string\>('greet', { name: 'YJ' })

Tauri 2 Mobile — strengths and weaknesses

  • Strengths — 6-8MB Android bundle, security (auto-CSP and a permission manifest), Rust backend (fast IO, crypto, DB access).
  • Weaknesses — UI performance still depends on the system WebView. Not great for 60fps games or complex animations. Some compatibility quirks on iOS 17 and earlier.

Who uses it

In 2026, Tauri Mobile is showing adoption in prosumer tools — secure key managers, local note apps, developer utilities. TikTok-scale consumer apps are still rare.


8. Capacitor 7 vs Cordova — Web-First Today

The two rivals of web-first mobile. Cordova effectively halted major updates in 2024, with the Apache Cordova project entering a retirement track. The web-first slot belongs to Capacitor 7 (built by the Ionic team).

Capacitor 7 essentials

  • iOS WKWebView / Android Chromium WebView hosting a web app.
  • Capacitor Plugins — camera, Bluetooth, push, file access exposed as JS APIs.
  • Ionic Framework sits on top as a UI kit (optional; works with React, Vue, or Angular).
// Capacitor camera usage
import { Camera, CameraResultType } from '@capacitor/camera'

const takePhoto = async () => {
  const photo = await Camera.getPhoto({
    quality: 90,
    allowEditing: false,
    resultType: CameraResultType.Uri,
  })
  return photo.webPath
}
# Basic setup
npm install @capacitor/core @capacitor/cli
npx cap init
npx cap add ios
npx cap add android
npm run build
npx cap copy
npx cap open ios

Who uses it

  • Ship a PWA into the stores fast — existing React or Vue app, need a store presence in one or two weeks.
  • Enterprise line-of-business apps — internal tools. Low perf demands, fast delivery.
  • Hybrid e-commerce — native checkout, web for everything else.

The App Store rejects thin webview wrappers more often these days, so Capacitor needs to demonstrate "hybrid value" — native features in use, offline behavior, app-like interactions.


9. Lynx (ByteDance) — TikTok's Internal Framework, Open Source

In March 2025 ByteDance open-sourced Lynx, the cross-platform framework powering TikTok, Lark, and Douyin internally. The implication is significant.

Why a new framework?

We already have RN and Flutter. Why? Paraphrasing ByteDance's stated rationale.

  • Main-thread protection — for infinite-scroll, short-video apps like TikTok, painting the first frame synchronously matters. RN's Fabric is good, but ByteDance wanted to be more aggressive about freeing the main thread.
  • Dual-thread model — separate the main thread (synchronous UI rendering) from a background thread (JS logic). The first frame is drawn synchronously.
  • PrimJS — Lynx's own JS engine (a QuickJS fork). AOT bytecode similar to Hermes.

A single line of Lynx code

import { View, Text, Image } from '@lynx-js/react'

export default function App() {
  return (
    <View style={{ padding: 20 }}>
      <Text style={{ fontSize: 24 }}>Hello Lynx</Text>
      <Image src="https://example.com/cat.jpg" style={{ width: 100, height: 100 }} />
    </View>
  )
}

On the surface it looks like RN — JSX and components. The differences live in the engine.

What's different

  • First frame synchronous — when a List first renders, layout and paint happen synchronously on the main thread.
  • Atomic CSS — Tailwind-like atomic CSS is a first-class citizen, processed at build time.
  • Rust core — some critical paths were rewritten in Rust.

Who is it for?

ByteDance built it for their own apps (TikTok-scale). That means it is tuned for massive traffic + infinite scroll + short videos. For general SaaS, e-commerce, and productivity apps, RN and Flutter remain the safer pick.

The real meaning of open-sourcing it is a public acknowledgment that "there are cases RN and Flutter cannot reach" and a leak of TikTok-grade know-how to the world. Late 2026 and 2027 will tell us who follows.


10. .NET MAUI / NativeScript — The Other Options

Two more options hold their lanes alongside the five contenders.

.NET MAUI — Microsoft's answer

The successor to Xamarin.Forms. C# plus XAML targeting iOS, Android, Windows, and macOS from one codebase.

<!-- MainPage.xaml -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
  <VerticalStackLayout>
    <Label Text="Hello, MAUI!" FontSize="32" />
    <Button x:Name="CounterBtn" Text="Click me" Clicked="OnCounterClicked" />
  </VerticalStackLayout>
</ContentPage>
  • Strengths — Visual Studio integration, the entire .NET library ecosystem, enterprise SSO and Active Directory in one line.
  • Weaknesses — not mobile-first by design, Xamarin baggage persists. Community velocity trails RN and Flutter.

NativeScript — still alive

A survivor from the Telerik era. TypeScript, Vue, Svelte, or Angular driving real native UI (UIView / View) directly.

  • Strengths — call iOS and Android APIs from JS without bridge code in many cases.
  • Weaknesses — small community. After RN's New Architecture, the differentiation feels thinner.

In May 2026 NativeScript is mostly used out of nostalgia for the pre-RN era. For new projects, RN, Flutter, or KMP usually come first.


11. How to Choose — A Decision Matrix

Line up the five contenders and two options across team, product, design, and bundle size.

By team

Team backgroundFirst pickSecond pickNote
Web (React/TS)React Native + ExpoCapacitor 7RN has the smoothest ramp
Web (Vue/Svelte)Capacitor 7Tauri 2 MobileWhen RN's React dependency irritates you
Kotlin / AndroidKMP + Compose MultiplatformFlutteriOS rollout can be gradual
iOS-heavyKMP (logic only)React NativeKeep SwiftUI as is
Dart / mobile-firstFlutterCompose MultiplatformPrioritize pixel consistency
C# / .NET.NET MAUIReact NativeEnterprise

By product

Product typeRecommendationWhy
Content / feed (TikTok-grade)Lynx or RNMain-thread protection
Games / interactive mediaFlutterPixel-perfect 60fps
FinTech / bankingRN (Expo) or KMPBig ecosystem, security libraries
E-commerceRN (Expo)Fast launch, ad SDK compatibility
Internal LOB appsCapacitor 7Fast delivery, low cost
Prosumer toolsTauri 2 MobileTiny bundle, security

By design

Design directionRecommendation
Strong OS look and feelRN, KMP (SwiftUI / Compose separately)
Brand pixel-perfectFlutter, Compose Multiplatform
Reuse web design directlyCapacitor, Tauri Mobile

By bundle size

FrameworkiOS empty appAndroid empty app
Tauri 2 Mobileabout 8MBabout 6MB
Capacitor 7about 10MBabout 8MB
KMP (logic sharing)about 12MBabout 7MB
React Native + Expoabout 15MBabout 13MB
Flutterabout 17MBabout 14MB
Compose Multiplatformabout 18MBabout 9MB

These are empty-app sizes. Real apps balloon two or three times with images, fonts, and libraries. Past 100MB you hit the App Store cellular-download cap and lose automatic 4G/5G installs.


12. Korean and Japanese Mobile Ecosystems — What They Actually Use

The theory table is the starting point; reality is different. Here's what big Korean and Japanese companies actually shipped as of May 2026 (based on public hiring posts, engineering blogs, and conference talks).

Korea

  • Kakao — Android uses Kotlin + Jetpack Compose, iOS uses Swift + SwiftUI. KMP (logic only) appears in some internal tools and new services. RN powers internal tooling and event-driven mini apps.
  • Naver — same direction. Core apps are native (Swift / Kotlin), with RN and Flutter postings showing up for validation-stage services.
  • Coupang — most aggressive RN adopter. Some search and listing screens are known to run on RN, on top of Hermes.
  • Toss — iOS Swift and Android Kotlin in the main app. Some internal and ops tools on RN.
  • Daangn (Karrot) — Flutter adoption is the most visible. Parts of the service (used goods + neighborhood) use Flutter.
  • Baemin (Woowa Brothers) — primarily native. Some new experiments on Flutter.

Japan

  • Mercari — Android team has shared KMP adoption multiple times at conferences. iOS stays Swift, Android stays Kotlin, with KMP sharing only business logic.
  • CyberAgent — many subsidiaries, lots of stack variety. AbemaTV is native with no RN / Flutter history. Some subsidiaries use Flutter.
  • DeNA — games and entertainment on Unity and native. Generic apps on Swift + Kotlin.
  • LINE Yahoo Japan — LINE itself is native. Some mini apps and campaign pages use WebViews.
  • PayPay — primarily native. RN / Flutter footprint is small.
  • freee / SmartHR / Money Forward — SaaS camp. Mobile apps mix RN and Flutter, with Flutter trending up for new projects.

Patterns across both markets

  • Core apps remain native. Super apps (KakaoTalk, LINE, PayCo) are almost entirely Swift + Kotlin.
  • RN and Flutter live in new and experimental services. New domains, mini apps, internal tools.
  • KMP is quietly growing. Sharing only business logic — Mercari and Kakao are the canonical examples.
  • Compose Multiplatform adoption is still conservative. With iOS stable landing in Q1 2026, serious adoption will likely surface in late 2026 and 2027.

Takeaway

Big companies adopt cross-platform only when "risk < code-sharing benefit." They keep native for apps where the core experience matters, and validate cross-platform in new features, experiments, and internal tools. KMP's logic-only sharing is the safest entry point.


Wrap-up — Checklist and Anti-Patterns

Decision checklist

  1. What is the team's primary language? (TS / Dart / Kotlin / Swift / C#)
  2. Is the design baseline OS-standard or brand pixel-perfect?
  3. Are the hero screens 60fps video and complex animation, or forms and lists?
  4. Do you have a bundle-size cap? (App Store cellular cap is 200MB)
  5. What is the balance between App Store / Play Store review speed and OTA updates?
  6. Do you already own web assets? (Capacitor / Tauri value increases)
  7. What are the security demands? (Tauri's Rust backend, or RN's security libraries)
  8. Who maintains the code five years from now?

Ten anti-patterns

  1. Running RN 0.76+ with the New Architecture disabled — unnecessary asymmetry.
  2. Starting on Expo and then ejecting and regretting it.
  3. Burning time making Flutter mimic native iOS look and feel.
  4. Copying the pattern of putting KMP UI sharing in production before stable (pre-2025).
  5. Forcing 60fps game animations on top of Capacitor.
  6. Trying to ship a TikTok-scale consumer app on Tauri Mobile.
  7. Adopting Lynx for small internal tools — overkill.
  8. Pinning the JS engine to JSC and never migrating to Hermes.
  9. Using EAS Update for a full UI redesign and risking App Store guidelines.
  10. Choosing .NET MAUI for a mobile-first design app and pushing desktop patterns on it.

Next-up ideas

Candidate follow-ups: React Native New Architecture migration in practice — a 0.74 to 0.76 walkthrough, Keep both SwiftUI and Compose alive with KMP logic-only sharing, Debugging Flutter Impeller shaders — taming the jank.

"Cross-platform isn't the magic of writing one codebase for two OSes — it's a negotiation about which costs you move and where."

— Cross-Platform Mobile Development 2026, fin.


References