이 튜토리얼에서는 Capacitor를 사용해 Vue 웹 애플리케이션을 네이티브 모바일 앱으로 변환하는 과정을 안내합니다. 네이티브 모바일 느낌을 위해 Capgo Native Navigation and Transitions를 추가하고, safe area 처리를 위해 tailwind-capacitor를 사용할 수 있습니다.
Capacitor 소개
Capacitor는 어떤 웹 프로젝트에도 쉽게 통합해 애플리케이션을 네이티브 모바일 앱으로 변환할 수 있는 판도를 바꾸는 도구입니다. Xcode 및 Android Studio용 네이티브 프로젝트를 생성해 주고, JavaScript 브리지를 통해 카메라와 같은 네이티브 디바이스 기능에 접근할 수 있습니다.
Vue 앱 준비하기
먼저 다음 명령어를 실행해 새 Vue 앱을 만드세요:
vue create my-app
cd my-app
npm install
Vue 앱을 네이티브 모바일 배포용으로 준비하려면 프로젝트를 export해야 합니다. 다음 스크립트를 package.json 파일에 추가해 Vue 프로젝트를 빌드하고 복사하세요:
{
"scripts": {
// ...
"build": "vue-cli-service build"
}
}
명령어를 실행한 후, build 프로젝트 루트 디렉토리에 새로운 dist 폴더가 생성된 것을 확인할 수 있습니다. 이 폴더는 나중에 Capacitor에서 사용됩니다.
Vue 앱에 Capacitor 추가하기
Vue 웹 앱을 네이티브 모바일 컨테이너로 변환하려면 다음 단계를 따르세요:
-
Capacitor CLI를 dev dependency로 설치하고 프로젝트에 설정하세요. 설정 과정에서 name과 bundle ID는 기본값을 사용하면 됩니다.
-
코어 패키지와 iOS 및 Android 플랫폼용 관련 패키지를 설치하세요.
-
플랫폼을 추가하면 Capacitor가 프로젝트 루트에 각 플랫폼별 폴더를 생성합니다:
# Install the Capacitor CLI locally
npm install -D @capacitor/cli
# Initialize Capacitor in your Vue project
npx cap init
# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android
# Add the native platforms
npx cap add ios
npx cap add android
이제 Vue 프로젝트에 새 iOS 및 Android 폴더가 표시되어야 합니다.
다음 파일을 업데이트하세요: capacitor.config.json 파일을 가리키도록 webDir 빌드 명령의 결과로 설정하세요:
{
"appId": "com.example.app",
"appName": "my-app",
"webDir": "dist"
}
이제 Vue 프로젝트를 빌드하고 Capacitor와 동기화할 수 있습니다:
npm run build
npx cap sync
Native App 빌드 및 배포
iOS 앱을 개발하려면 Xcode가, Android 앱을 개발하려면 Android Studio가 설치되어 있어야 합니다. 또한 앱 스토어에 앱을 배포하려면 iOS는 Apple Developer Program에, Android는 Google Play Console에 등록해야 합니다.
Capacitor CLI를 사용하여 두 네이티브 프로젝트를 모두 여세요:
npx cap open ios
npx cap open android
Android Studio 또는 Xcode를 사용하여 연결된 기기에 앱을 배포하세요.
Capacitor Live Reload
Capacitor 앱이 네트워크상의 특정 URL에서 콘텐츠를 로드하도록 설정하여 모바일 기기에서 live reload를 활성화하세요.
로컬 IP 주소를 찾아 다음 capacitor.config.ts 파일을 올바른 IP와 포트로 업데이트하세요:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'my-app',
webDir: 'dist',
bundledWebRuntime: false,
server: {
url: 'http://192.168.x.xx:8080',
cleartext: true
}
};
export default config;
변경 사항을 네이티브 프로젝트로 복사하여 적용하세요:
npx cap copy
이제 Vue 앱을 업데이트하면 앱이 자동으로 리로드되어 변경 사항이 반영됩니다.
Capacitor 플러그인 사용법
Share plugin 같은 Capacitor 플러그인을 설치하고 Vue 앱에서 사용하세요:
npm i @capacitor/share
패키지를 import하고 share() 앱에서 다음 기능을 사용할 수 있습니다:
<template>
<div>
<h1>Welcome to Vue and Capacitor!</h1>
<button @click="share">Share now!</button>
</div>
</template>
<script setup lang="ts">
import { Share } from '@capacitor/share';
async function share() {
await Share.share({
title: 'Open Youtube',
text: 'Check new video on youtube',
url: 'https://www.youtube.com',
dialogTitle: 'Share with friends'
});
}
</script>
새 플러그인을 설치한 후 sync 명령을 실행하고 앱을 기기에 다시 배포하세요:
npx cap sync
다음으로, Capgo 내비게이션과 트랜지션으로 iOS와 Android에서 앱을 더 네이티브하게 느끼게 하고, 가로 오버플로우나 세이프 에어리어가 잘리는 흔한 iOS 레이아웃 문제도 해결할 수 있습니다.
Capgo Native Navigation and Transitions로 만드는 네이티브한 UI
저는 수년간 Ionic 크로스 플랫폼 애플리케이션을 구축하는 데 사용할 수 있지만, 이미 다른 도구가 있다면 Vue와 통합하는 것은 해킹 방식에 가깝고 거의 가치가 없습니다 Tailwind CSS.
Vue + Capacitor 앱에서 네이티브 모바일 느낌을 원한다면, Konsta UI 같은 웹 전용 UI 키트 대신 Capgo 플러그인을 사용하세요:
- @capgo/capacitor-native-navigation — 네이티브 내비게이션 바, iOS의 Liquid Glass 탭 바, Android의 블러 탭 바 스타일. Vue 라우터는 라우트 상태를 유지하고, 플러그인이 네이티브 크롬을 관리합니다.
- @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
다음에서 src/assets/main.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
다음과 같은 유틸리티를 사용하세요: pt-safe, pb-safe, 그리고 px-safe 여기저기 흩뿌리는 대신 env(safe-area-inset-*) 수동으로 작업할 필요가 없습니다. 이 프로젝트는 활발히 개발 중이며, Vue 설정에 빠진 게 있다면 GitHub에 PR을 올려주세요..
iOS 레이아웃 이슈 해결 (Viewport, Safe Area, 가로 오버플로우)
iOS에서 콘텐츠가 잘리거나, 밀리거나, 가로 스크롤이 생긴다면, 더 추가하거나 overflow-x: hidden viewport 태그를 조정하는 것만으로는 보통 해결되지 않습니다. 다음 점검을 순서대로 진행하세요.
viewport meta 태그가 올바르게 적용되었는지 확인하세요
다음 위치에 viewport meta 태그를 추가하세요 index.html 내부에서 <head>:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
iOS safe area는 루트 래퍼 한 곳에서만 처리하세요
단일 앱 셸을 생성하고 그곳에 safe area 패딩을 적용하세요. 여러 중첩된 컴포넌트에 각각 적용하지 마세요:
html,
body,
#app {
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: 'dist',
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는 기존 웹 프로젝트를 기반으로 네이티브 앱을 구축하는 데 훌륭한 선택지입니다. Capgo를 추가하면 앱에 Live Update를 적용하는 것이 더욱 쉬워지며, 사용자가 항상 최신 기능과 버그 수정을 누릴 수 있도록 보장합니다.
Capgo로 더 나은 앱을 더 빠르게 빌드하는 방법을 알아보세요. 무료 계정 가입하기 만들어 보세요.
Vue와 Capacitor로 모바일 앱 만들기에서 이어서 계속하기
사용 중이라면 Vue와 Capacitor로 모바일 앱 구축하기 네이티브 미디어 및 인터페이스 동작을 계획하려면, 이를 다음 항목과 연결하세요: @capgo/capacitor-live-activities 사용 @capgo/capacitor-live-activities 사용에서의 네이티브 기능, @capgo/capacitor-live-activities @capgo/capacitor-live-activities의 구현 세부 사항, @capgo/capacitor-video-player 사용 @capgo/capacitor-video-player 사용 시 네이티브 기능은, @capgo/capacitor-video-player 구현 세부 사항은 @capgo/capacitor-video-player에서 확인하고, @capgo/capacitor-native-navigation 사용하기 @capgo/capacitor-native-navigation. 사용 시의 Native 기능