소개
이미 운영 중인 Nuxt 웹 애플리케이션이 있으신가요? 이 가이드에서는 다음 도구들을 사용하여 Nuxt 앱을 iOS 및 Android 네이티브 모바일 앱으로 전환하는 방법을 알아봅니다. Capacitor 8 — 성능이 개선되고 새로운 기능이 추가된 최신 버전입니다.
Capacitor는 기존 Vue codebase를 그대로 유지하면서 웹 앱을 native container로 감싸줍니다. 이를 통해 카메라, filesystem, push notifications와 같은 device API에 접근할 수 있습니다. Flutter나 React Native와 달리 코드를 다시 작성할 필요가 없습니다. 여러분의 Nuxt code는 있는 그대로 실행됩니다.
학습 내용:
- 기존 Nuxt 앱을 static generation용으로 설정하기
- 필수 native plugins와 함께 Capacitor 8 추가하기
- iOS와 Android 시뮬레이터에서 빌드하고 테스트하기
- 빠른 개발을 위한 live reload 활성화하기
- 자주 겪는 iOS 레이아웃 문제 해결하기 (viewport, safe area, horizontal overflow)
- Capgo Native Navigation and Transitions로 네이티브 느낌의 UI 추가하기
새 프로젝트를 처음부터 시작하려고요? 다음 가이드를 확인해 보세요: Nuxt 모바일 앱 처음부터 빌드하기.
Nuxt와 Capacitor 사용 시 장점
- Code 재사용성: Vue 컴포넌트와 로직을 웹과 모바일 앱 간에 공유하세요.
- 성능: Nuxt의 정적 생성을 통해 모바일에 최적화된 번들을 만듭니다.
- Native 기능 활용: Capacitor 플러그인을 통해 카메라, 위치 정보, 파일 시스템 등 기기 기능을 사용하세요.
- 간편한 개발 환경: 네이티브 개발을 새로 배울 필요 없이 익숙한 Vue/Nuxt 패턴을 그대로 사용하세요.
사전 요구사항
시작하기 전에 다음 사항을 확인하세요:
- Node.js 18 이상 설치되어 있는지
- 기존에 설치된 Nuxt 4 애플리케이션
- iOS 프로파일링 (iOS 개발용, macOS 전용)
- Android Studio (Android 개발용)
Nuxt 앱 모바일 설정하기
첫 번째 단계는 Nuxt 앱을 정적 생성(static generation)하도록 설정하는 것입니다. Capacitor가 네이티브 앱으로 번들링하려면 정적 HTML/JS/CSS 파일이 필요합니다.
다음 설정값 package.json 다음과 같은 generate 스크립트가 있습니다:
{
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"mobile": "bun run generate && bunx cap sync",
"mobile:ios": "bun run mobile && bunx cap open ios",
"mobile:android": "bun run mobile && bunx cap open android"
}
}
중요: 서버 사이드 기능(API 라우트, 서버 미들웨어 등)을 사용 중이라면, 이를 클라이언트 사이드 방식이나 외부 API를 사용하도록 리팩터링해야 합니다.
다음 명령어를 실행해 정적 생성을 테스트하세요:
bun run generate
다음이 보일 것입니다: .output/public 정적 파일이 포함된 폴더입니다. 이 폴더가 Capacitor를 통해 native app에 bundle됩니다.
프로젝트에 Capacitor 8 추가하기
Nuxt 앱을 native mobile 컨테이너로 패키징하려면 다음 단계를 따르세요:
- Capacitor core와 CLI를 설치하세요:
bun add @capacitor/core
bun add -D @capacitor/cli
- 자주 필요할 Capacitor 플러그인을 설치하세요:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences
이 플러그인들은 다음과 같은 필수 기능을 제공합니다:
- @capacitor/app: 앱 라이프사이클 이벤트 처리 (foreground/background, deep links)
- @capacitor/keyboard: 모바일 키보드 동작 제어
- @capacitor/splash-screen: 네이티브 스플래시 화면 관리
- @capacitor/status-bar: 디바이스 상태 표시줄 스타일링
- @capacitor/preferences: 키-값 저장소 (localStorage와 유사한 네이티브 방식)
- 프로젝트 정보로 Capacitor를 초기화하세요:
bunx cap init my-app com.example.myapp --web-dir .output/public
교체 my-app 앱 이름과 함께 com.example.myapp 앱 ID(역도메인 표기법)와 함께.
- 다음 설정을 사용하여
capacitor.config.ts파일을 생성하거나 업데이트하세요:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: '.output/public',
plugins: {
SplashScreen: {
launchShowDuration: 2000,
launchAutoHide: true,
androidScaleType: 'CENTER_CROP',
splashFullScreen: true,
splashImmersive: true,
},
Keyboard: {
resize: 'body',
resizeOnFullScreen: true,
},
StatusBar: {
style: 'dark',
},
},
};
export default config;
- 네이티브 플랫폼 설치:
bun add @capacitor/ios @capacitor/android
- 네이티브 플랫폼 폴더 추가:
bunx cap add ios
bunx cap add android
Capacitor 명령어를 실행하면 ios 및 android 프로젝트 루트에 네이티브 프로젝트가 포함된 폴더가 생성됩니다.
Android 프로젝트를 빌드하려면 Android Studio가필요합니다. iOS의 경우 Mac과 iOS 프로파일링.
- 프로젝트 빌드 및 동기화:
bun run mobile
이 명령은 정적 Nuxt 빌드를 생성하고 파일을 네이티브 플랫폼과 동기화하는 커스텀 스크립트를 실행합니다.
네이티브 앱 빌드 및 배포
네이티브 모바일 앱을 빌드하고 배포하려면 다음 단계를 따르세요:
iOS 앱을 개발하려면 다음이 필요합니다: iOS 프로파일링 가 설치되어 있어야 하며, Android 앱의 경우 Android Studio 가 설치되어 있어야 합니다. 또한 앱을 스토어에 배포하려면 iOS는 Apple Developer Program에, Android는 Google Play Console에 등록해야 합니다.
- 네이티브 프로젝트를 여세요:
iOS의 경우:
bun run mobile:ios
Android의 경우:
bun run mobile:android
또는 Capacitor CLI로 직접 실행하세요:
bunx cap open ios
bunx cap open android
- 앱 빌드 및 실행:

- Android Studio에서 프로젝트가 준비될 때까지 기다린 다음, “Run” 버튼을 클릭해 연결된 기기나 에뮬레이터에 앱을 배포하세요.

- Xcode에서 실제 기기에 앱을 배포하려면 signing account를 설정해야 합니다. 처음이라면 Xcode의 안내에 따라 설정을 진행하세요 (Apple Developer Program 등록이 필요합니다). 설정이 완료되면 “Play” 버튼을 클릭해 연결된 기기에서 앱을 실행하세요.
축하합니다! Nuxt 웹 앱을 모바일 기기에 성공적으로 배포했습니다.
잠깐만요, 개발 중에는 이보다 더 빠른 방법이 있습니다...
Capacitor Live Reload
개발 중에는 live reloading을 활용해 변경 사항을 모바일 기기에서 즉시 확인할 수 있습니다. 이 기능을 사용하려면 다음 단계를 따르세요:
- 로컬 IP 주소를 확인하세요:
-
macOS에서는 터미널에서 다음 명령어를 실행하세요:
ipconfig getifaddr en0 -
Windows에서는 다음을 실행하세요:
ipconfig출력에서 IPv4 주소를 확인하세요.
- 다음 파일을
capacitor.config.ts개발 서버를 가리키도록 하려면:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'my-app',
webDir: '.output/public',
server: {
url: 'http://YOUR_IP_ADDRESS:3000',
cleartext: true,
},
plugins: {
// ... your plugin config
},
};
export default config;
교체 YOUR_IP_ADDRESS 로컬 IP 주소로 (예: 192.168.1.100).
- 변경 사항을 네이티브 프로젝트에 적용하세요:
bunx cap copy
이 copy 이 명령은 전체 프로젝트를 업데이트하지 않고 web 폴더와 설정 변경 사항만 네이티브 프로젝트로 복사합니다.
- Nuxt 개발 서버를 실행하고 Xcode/Android Studio에서 다시 빌드하세요:
bun run dev
이제 Nuxt 앱을 수정할 때마다 모바일 앱이 자동으로 새로고침되어 변경 사항이 즉시 반영됩니다.
참고: 새 플러그인을 설치하거나 네이티브 파일을 수정하는 경우에는 네이티브 프로젝트를 다시 빌드해야 합니다. 라이브 리로딩은 웹 code 변경 사항에만 적용되기 때문입니다.
Capacitor 플러그인 사용법
Capacitor plugins를 사용하면 Nuxt 앱에서 네이티브 디바이스 기능을 사용할 수 있습니다. 다음은 그 사용 방법입니다. 플러그인 공유하기 예시:
- Share 플러그인 설치:
bun add @capacitor/share
- Share plugin을 사용하기 위해 페이지를 생성하거나 업데이트합니다. Nuxt 4에서 페이지는 다음 경로에 위치합니다.
app/pages/:
<template>
<div class="p-6">
<h1 class="text-2xl font-bold mb-4">Welcome to Nuxt + Capacitor!</h1>
<button
@click="shareContent"
class="px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold"
>
Share now!
</button>
</div>
</template>
<script setup lang="ts">
import { Share } from '@capacitor/share';
async function shareContent() {
await Share.share({
title: 'Check this out!',
text: 'Built with Nuxt and Capacitor',
url: 'https://capacitorjs.com',
dialogTitle: 'Share with friends',
});
}
</script>
- 변경 사항을 네이티브 프로젝트와 동기화:
bun run mobile
또는 재빌드 없이 동기화만:
bunx cap sync
- 앱을 재빌드하고 디바이스에서 실행하세요.
이제 “Share now!” 버튼을 클릭하면 네이티브 공유 다이얼로그가 나타납니다.
다음으로, Capgo 내비게이션과 트랜지션으로 iOS와 Android에서 앱을 더 네이티브하게 느끼게 하고, 가로 오버플로우나 세이프 에어리어가 잘리는 흔한 iOS 레이아웃 문제도 해결할 수 있습니다.
Capgo Native Navigation and Transitions로 만드는 네이티브한 UI
저는 수년간 Ionic는 크로스 플랫폼 앱을 빌드할 때 사용하지만, 이미 사용 중인 환경이 있다면 Nuxt와 통합하는 방식은 다소 임시방편적이며 그만한 가치가 없는 경우가 많습니다. Tailwind CSS.
Nuxt + Capacitor 앱에서 네이티브 모바일 느낌을 구현하려면, Konsta UI 같은 웹 전용 UI 키트 대신 Capgo 플러그인을 사용하세요:
- @capgo/capacitor-native-navigation — iOS의 네이티브 navbar와 Liquid Glass tab bar, Android의 블러 처리된 tab bar 스타일을 제공합니다. Nuxt router는 라우트 상태를 관리하고, 플러그인은 네이티브 chrome을 제어합니다.
- @capgo/capacitor-transitions — Ionic UI 없이 WebView 레이어에서 Ionic 스타일 페이지 전환과 iOS edge swipe-back을 제공합니다.
둘 다 설치하세요:
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
웹 콘텐츠가 native bar를 침범하지 않도록 CSS inset 모드로 native navigation을 설정하세요:
import { NativeNavigation } from '@capgo/capacitor-native-navigation';
await NativeNavigation.configure({
contentInsetMode: 'css',
animationDuration: 360,
glass: {
effect: 'liquidGlass',
},
});
Liquid Glass tab bar를 렌더링합니다 (iOS는 시스템이 렌더링하고, Android는 블러 처리된 WebView 배경을 사용합니다):
await NativeNavigation.setTabbar({
selectedId: 'home',
labelVisibilityMode: 'labeled',
icons: true,
colors: { dynamic: true },
tabs: [
{ id: 'home', title: 'Home', icon: { svg: '...' } },
{ id: 'settings', title: 'Settings', icon: { svg: '...' } },
],
});
await NativeNavigation.addListener('tabSelect', ({ id }) => {
router.push(`/${id}`);
});
앱 shell에 native page transitions를 추가하세요:
<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/vue';
initTransitions({ platform: 'auto' });
const router = useRouter();
const outletRef = ref(null);
onMounted(() => {
if (outletRef.value) {
setupRouterOutlet(outletRef.value, { platform: 'auto', swipeGesture: 'auto' });
}
});
const openSettings = () => {
setDirection('forward');
router.push('/settings');
};
</script>
<template>
<cap-router-outlet ref="outletRef">
<router-view />
</cap-router-outlet>
</template>
라우팅된 페이지를 cap-router-outlet, cap-page, 그리고 cap-content로 감싸고, 호출하세요 setDirection('forward') 또는 setDirection('back') 이동하기 전에. 네이티브 네비게이션이 해당 영역을 담당할 때는 웹 헤더나 푸터를 중복해서 만들지 마세요.
전체 가이드 보기: @capgo/capacitor-native-navigation 사용하기 및 @capgo/capacitor-transitions 사용하기.
Tailwind로 safe area 처리하기
Tailwind CSS에서 디바이스 safe area에는 다음을 사용하세요: @capgo/tailwind-capacitor (다음으로 게시됨: tailwind-capacitor npm). 다음을 제공합니다: safe-areas 유틸리티와 기타 Capacitor 친화적인 Tailwind 플러그인:
bun add -D tailwind-capacitor
다음에서 app/assets/css/main.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
Tailwind CSS 4를 사용하는 Nuxt 4의 경우, 다음 import 문을 CSS 파일에 직접 유지해 주세요. nuxt.config.ts.
다음과 같은 유틸리티를 사용하세요: pt-safe, pb-safe, 그리고 px-safe 여기저기 흩뿌리는 대신 env(safe-area-inset-*) 이 프로젝트는 활발히 개발 중입니다. Nuxt 설정에 필요한 내용이 누락되었다면, GitHub에 PR을 올려주세요..
iOS 레이아웃 이슈 해결 (Viewport, Safe Area, 가로 오버플로우)
iOS에서 콘텐츠가 잘리거나, 밀리거나, 가로 스크롤이 생긴다면, 더 추가하거나 overflow-x: hidden viewport 태그를 조정하는 것만으로는 보통 해결되지 않습니다. 다음 점검을 순서대로 진행하세요.
viewport meta 태그가 올바르게 적용되었는지 확인하세요
다음에서 nuxt.config.ts, viewport는 다음을 통해 설정하세요 app.head:
export default defineNuxtConfig({
app: {
head: {
meta: [
{
name: 'viewport',
content: 'width=device-width, initial-scale=1, viewport-fit=cover',
},
],
},
},
});
iOS safe area는 루트 래퍼 한 곳에서만 처리하세요
단일 앱 셸을 생성하고 그곳에 safe area 패딩을 적용하세요. 여러 중첩된 컴포넌트에 각각 적용하지 마세요:
html,
body,
#__nuxt {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow-x: hidden;
}
* {
box-sizing: border-box;
}
.app-shell {
min-height: 100dvh;
width: 100%;
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
모든 페이지 콘텐츠를 다음 안에 감싸세요: .app-shell. 헤더, 모달, 레이아웃 래퍼에 safe-area 패딩이 중복되면 UI가 잘리거나 너무 커 보일 수 있습니다.
사용하면 @capgo/tailwind-capacitor, 다음과 같은 유틸리티로 동일한 패딩을 표현할 수 있습니다. pt-safe pb-safe px-safe 해당 단일 셸에서.
Capacitor iOS를 설정하세요 contentInset 대상 never 먼저
다음에서 capacitor.config.ts, native inset을 비활성화하는 편이 좋고 CSS(또는 Native Navigation의 contentInsetMode: 'css')가 safe area를 제어하도록 하세요:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'out',
ios: {
contentInset: 'never',
},
};
Capacitor의 자동 content inset과 CSS env(safe-area-inset-*) padding을 함께 쓰면 이중 여백이 생기는 흔한 원인입니다.
실제로 overflow되는 요소를 찾으세요
흔한 원인은 다음을 사용하는 요소입니다: 100vw, Tailwind w-screen, 고정 픽셀 너비 또는 큰 min-width.
Safari Web Inspector에서 다음을 실행하세요:
[...document.querySelectorAll('*')]
.filter(el => el.scrollWidth > document.documentElement.clientWidth)
.map(el => ({
el,
tag: el.tagName,
class: el.className,
scrollWidth: el.scrollWidth,
clientWidth: document.documentElement.clientWidth,
}));
Tailwind에서는 다음을 교체하세요: w-screen 포함 w-full 가능하면 사용하세요. 많은 가로 오버플로 문제는 100vw / w-screen중복된 safe-area 패딩이나 고정 너비 컨테이너 때문이며, viewport meta tag 자체 때문은 아닙니다.
마치며
Capacitor 8을 사용하여 기존 Nuxt 웹 애플리케이션을 iOS 및 Android 네이티브 앱으로 성공적으로 전환했습니다. 이제 Vue 코드베이스가 디바이스 API에 접근하며 모바일 기기에서 네이티브로 실행됩니다.
완료한 작업:
- 정적 생성을 위한 Nuxt 설정
- 필수 플러그인을 포함한 Capacitor 8 추가
- iOS 및 Android 시뮬레이터 빌드 및 배포
- 개발을 위한 live reload 활성화
- 흔한 iOS 레이아웃 이슈 해결 (viewport, safe area, overflow)
- Capgo Native Navigation 및 Transitions를 통한 네이티브 UI 구현
다음 단계:
- 설정하기 Capgo 스토어 재심사 없는 OTA 업데이트를 위해
- Camera, Geolocation, Push Notifications 등 네이티브 플러그인 추가
- 프로덕션용 앱 아이콘 및 스플래시 스크린 설정
- App Store 및 Google Play 출시 준비
새 프로젝트를 시작하시나요? 다음을 확인해 보세요: Nuxt 모바일 앱 처음부터 만들기 단계별 가이드 확인하기
리소스
- Nuxt 문서
- Capacitor 8 문서
- @capgo/capacitor-native-navigation — Liquid Glass 탭 바 및 네이티브 크롬
- @capgo/capacitor-transitions — 네이티브 느낌의 페이지 전환
- @capgo/tailwind-capacitor — Capacitor를 위한 Tailwind safe-area 유틸리티
- Capgo - Capacitor 앱을 위한 Live Updates
Capgo로 더 나은 앱을 더 빠르게 빌드하는 방법을 알아보세요. 무료 계정 가입하기 만들어 보세요.
Capacitor를 사용하여 Nuxt 앱을 iOS 및 Android로 변환하기 단계에서 계속하기
사용 중이라면 Capacitor로 Nuxt 앱을 iOS 및 Android로 전환하기 8 네이티브 플러그인 작업을 계획하려면, 이를 다음 항목과 연결하세요: Capgo 플러그인 디렉토리 Capgo Plugin Directory의 제품 워크플로우에 맞춰, Capgo의 Capacitor 플러그인 Capgo의 Capacitor 플러그인 구현 상세 내용에 대해서는, 플러그인 추가 또는 업데이트 플러그인 추가 또는 업데이트의 구현 세부 사항은, Ionic Enterprise 플러그인 대안 Ionic Enterprise 플러그인 대안의 제품 워크플로우와, Capgo Native Build Capgo Native Builds의 제품 워크플로우를 위해.