2026 모바일 앱 개발 완전 가이드

Flutter·React Native·KMP·네이티브 선택 기준

by AI개발자
소프트웨어엔지니어링_0.png
이 장을 읽기 전에: 프론트엔드 개발의 기본 개념(3장)을 파악하고 있으면 이해하기 쉽다. 다만, 모바일 개발 경험이 없어도 읽을 수 있는 구성으로 되어 있다.


모바일 개발에서 처음으로 결정해야 할 것은 언어나 프레임워크가 아니다. 먼저 결정해야 할 것은 어떤 배포 경로를 사용하는가, 어디까지 단말 기능을 사용하는가, 기존 팀의 강점을 어디에 두는가 의 3가지다.

웹 서비스의 연장으로 시작한다면 PWA로 충분한 경우도 있다. 한편 알림, 인앱 결제, 카메라, 백그라운드 처리, 스토어 배포, 단말 고유의 조작감까지 요구한다면 네이티브 앱이나 크로스플랫폼 앱을 전제로 생각하는 편이 좋다.

� 한국 시장 특이점: 한국은 Android 점유율이 약 70%(삼성·LG 중심), iOS가 약 30%다. 카카오·네이버·라인 등 국내 주요 기업은 Android와 iOS를 모두 운영하며, 배달의민족·당근마켓·토스 등은 네이티브 또는 크로스플랫폼(Flutter/React Native)을 주력으로 사용한다.



1. 네이티브 vs 크로스플랫폼 판단 기준

이 섹션이 답하는 질문: iOS와 Android를 별도로 만들어야 하는가, 하나의 접근 방식으로 양쪽을 다뤄야 하는가?


왜 처음에 여기를 결정하는가

모바일 개발은 기술 선정을 잘못하면 나중에 수정하기 어렵다. 특히 다음 3가지는 초기 판단의 영향이 크다.

배포 경로 (스토어 vs PWA)

하드웨어 기능에 대한 의존도 (카메라, NFC, 블루투스, 생체인증 등)

팀의 기존 스킬 (웹 개발자 vs 모바일 전담)


앱 스토어 배포가 불필요하고 알림이나 오프라인도 한정적이라면 PWA로 충분한 경우가 있다. 반대로, 스토어 인앱 결제, 무거운 애니메이션, AR, 블루투스, 백그라운드 실행 등이 중요하다면 처음부터 네이티브 또는 네이티브 방향의 구성을 선택하는 편이 재작업이 적다.


swe-2026-06-01.png


판단 플로

swe-2026-06-02.png


⚠️ 소규모 팀은 먼저 배포 경로와 기존 스킬로 좁히면 판단이 빠르다. 그 위에서 단말 고유 요건이 강하다면 네이티브로 기울인다는 순서로 하면 실패하기 어렵다.


비즈니스 관점 비교

swe-2026-06-03.png


정리

정답은 하나가 아니다. 단 다음 정리는 꽤 안정적이다.

PWA: 배포 속도와 웹 재이용을 최우선할 때

크로스플랫폼: 소인원으로 iOS / Android를 동시에 육성하고 싶을 때

네이티브: UX와 단말 통합이 경쟁력 그 자체가 될 때



2. 크로스플랫폼 프레임워크

이 섹션이 답하는 질문: Expo / React Native, Flutter, Kotlin Multiplatform은 어떻게 다른가?
swe-2026-06-04.png
� 국내 채용 및 사용 현황:
- Flutter: 카카오, 배달의민족(일부), 국내 스타트업에서 활발히 채택. 당근마켓이 Flutter 전환 사례를 공개 블로그에서 소개
- React Native: 국내 중소 IT 기업, 에이전시 위주. 네이버 일부 서비스에서 사용
- KMP: 카카오·라인 등 Kotlin 강팀 위주로 도입 검토 증가


Expo / React Native

Expo는 "네이티브 기능을 사용할 수 없는 간이판"이라는 이해로는 이제 불충분하다. 현재는 prebuild, config plugin, Expo Modules에 의해 많은 네이티브 연계를 단계적으로 다룰 수 있다.

따라서 React / TypeScript 팀이 모바일에 참입한다면, 먼저 Expo에서 시작하는 판단은 상당히 합리적이다.

단, 다음 요건이 강해질수록 빠르게 네이티브 경계를 명시하는 편이 좋다.

독자 네이티브 모듈

저수준의 블루투스 / NFC / 센서 처리

스토어 배포 전제에서의 세밀한 빌드 차이 관리

React Native 라이브러리 호환성 검증


⚠️ Expo에서 시작해 필요해지면 네이티브 측으로 내려가는 단계적 진행은 타당하다. 단 "언제든지 무통으로 내려갈 수 있다"고 생각하는 것은 위험하며, 이른 단계에서 의존 라이브러리의 대응 상황을 확인할 필요가 있다.



// Expo Router v3 — App Router 방식 파일 기반 라우팅

// app/(tabs)/index.tsx — 탭 홈 화면

import { StyleSheet, Text, View } from 'react-native';


export default function HomeScreen() {

return (

<View style={styles.container}>

<Text style={styles.title}>홈</Text>

</View>

);

}


const styles = StyleSheet.create({

container: { flex: 1, alignItems: 'center', justifyContent: 'center' },

title: { fontSize: 24, fontWeight: 'bold' },

});



Flutter

Flutter는 UI를 강하게 제어하고 싶은 안건과 궁합이 좋다. 독자 렌더링(Impeller 엔진)에 의해 OS 차이를 흡수하면서 일관된 외관을 만들기 쉽다.

적합한 장면은 다음과 같다.

디자인 재현성을 중시한다

Android와 iOS에서 외관을 맞추고 싶다

애니메이션이나 커스텀 UI가 많다

웹 팀 자산보다 모바일 체험을 우선한다


// Flutter 3.x — Riverpod + Freezed 패턴 (국내 스타트업 표준)

@freezed

class ProductState with _$ProductState {

const factory ProductState.initial() = _Initial;

const factory ProductState.loading() = _Loading;

const factory ProductState.loaded(List<Product> products) = _Loaded;

const factory ProductState.error(String message) = _Error;

}


@riverpod

class ProductNotifier extends _$ProductNotifier {

@override

ProductState build() => const ProductState.initial();


Future<void> fetchProducts() async {

state = const ProductState.loading();

try {

final products = await ref.read(productRepositoryProvider).getAll();

state = ProductState.loaded(products);

} catch (e) {

state = ProductState.error('상품을 불러오는 데 실패했습니다: $e');

}

}

}



Kotlin Multiplatform

Kotlin Multiplatform은 UI를 완전히 공유하는 기술이라기보다, 비즈니스 로직 공유의 기술로 이해하는 편이 실무에서는 안전하다.

특히 다음 공유에 적합하다.

API 클라이언트

인증이나 권한 규칙

유효성 검사

캐시 전략

도메인 로직

ViewModel 상당의 상태 관리


그 위에서 UI는 SwiftUI와 Jetpack Compose로 각각 만든다. 이 형태가 가장 안정적이다.


성능을 볼 때의 관점

swe-2026-06-05.png

정리

Expo / React Native: 웹 팀이 최단으로 참입하고 싶다

Flutter: UI 제어를 강하게 갖고 싶다

KMP: 네이티브 UI를 유지하면서 로직을 공유하고 싶다



3. 네이티브 개발

이 섹션이 답하는 질문: 네이티브 개발을 선택한다면 무엇을 사용하는가?
swe-2026-06-06.png


2026년 시점의 실무 포인트

iOS

SwiftUI는 중심적인 UI 프레임워크가 되고 있지만, 기존 자산이나 일부 고급 부품에서는 UIKit의 이해가 아직 필요하다. 또한 최신 Swift 계열에서는 동시성 체크가 강화되어 있어 오래된 코드를 그대로 이식하면 경고나 수정이 늘어나는 경우가 있다.


// SwiftUI + Swift Concurrency + Observation 패턴 (iOS 17+)

import SwiftUI

import Observation


@Observable

class ProductViewModel {

var products: [Product] = []

var isLoading = false

var errorMessage: String?


func loadProducts() async {

isLoading = true

defer { isLoading = false }


do {

products = try await ProductService.shared.fetchAll()

} catch {

errorMessage = "상품 목록을 불러오지 못했습니다."

}

}

}


struct ProductListView: View {

@State private var viewModel = ProductViewModel()


var body: some View {

NavigationStack {

Group {

if viewModel.isLoading {

ProgressView("불러오는 중...")

} else {

List(viewModel.products) { product in

지금 바로 작가의 멤버십 구독자가 되어
멤버십 특별 연재 콘텐츠를 모두 만나 보세요.

brunch membership
AI개발자작가님의 멤버십을 시작해 보세요!

AI Workflow Architect, LLM Engineer, Vibe Engineering, Claude Code, AI 업무 자동화 컨설팅/AI강의

83 구독자

오직 멤버십 구독자만 볼 수 있는,
이 작가의 특별 연재 콘텐츠

  • 최근 30일간 24개의 멤버십 콘텐츠 발행
  • 총 44개의 혜택 콘텐츠
최신 발행글 더보기
이전 05화2026 데이터베이스 선택 완전 가이드