본문 바로가기
튜토리얼

Vue와 Capacitor로 모바일 앱 구축하기

Vue와 Capacitor를 사용해 모바일 앱을 만드는 방법을 배우고, 원한다면 Capgo Native Navigation, Transitions, iOS 레이아웃 베스트 프랙티스까지 적용해 보세요.

Vue와 Capacitor로 모바일 앱 구축하기

Capacitor를 사용하여 Vue 웹 애플리케이션을 네이티브 모바일 앱으로 변환하는 과정을 안내합니다. Capgo Native Navigation and Transitions를 추가해 네이티브 앱의 느낌을 살릴 수 있으며, tailwind-capacitor로 세이프 에어리어(safe areas)를 처리할 수도 있습니다.

Capacitor 소개

Capacitor는 어떤 웹 프로젝트에도 쉽게 통합하여 애플리케이션을 네이티브 모바일 앱으로 변환할 수 있는 혁신적인 도구입니다. Xcode 및 Android Studio 프로젝트를 자동으로 생성하며, JavaScript bridge를 통해 카메라와 같은 네이티브 디바이스 기능에 접근할 수 있습니다.

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 웹 앱을 네이티브 모바일 컨테이너로 변환하려면 다음 단계를 따르세요:

  1. Capacitor CLI를 dev dependency로 설치하고 프로젝트에 설정하세요. 설정 과정에서 name과 bundle ID는 기본값을 사용하면 됩니다.

  2. 코어 패키지와 iOS 및 Android 플랫폼용 관련 패키지를 설치하세요.

  3. 플랫폼을 추가하면 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 폴더가 생성된 것을 확인할 수 있습니다.

Update the capacitor.config.json webDir 설정을 webDir build 명령의 결과에 다음과 같이 추가하세요:

{
  "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 Plugins 사용하기

Share plugin과 같은 Capacitor plugin을 설치하고 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 및 Transitions를 통한 네이티브 UI

저는 수년간 Ionic 을 사용하여 크로스 플랫폼 앱을 구축해 왔지만, 이미 Tailwind CSS.

를 사용 중이라면 Vue + Capacitor 앱에서 네이티브 모바일 느낌을 내기 위해 Konsta UI 같은 웹 전용 UI 키트 대신 Capgo 플러그인을 사용하세요:

  • @capgo/capacitor-native-navigation — 네이티브 navbar, iOS의 Liquid Glass tab bar, Android의 블러 처리된 tab bar 스타일을 제공합니다. Vue router는 라우트 상태를 유지하며, 플러그인이 네이티브 chrome을 제어합니다.
  • @capgo/capacitor-transitions — Ionic UI를 사용하지 않고도 WebView 레이어에서 Ionic 스타일의 페이지 전환과 iOS 엣지 스와이프 뒤로 가기를 구현합니다.

다음 두 가지를 모두 설치하세요:

bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync

웹 콘텐츠가 네이티브 바 영역을 침범하지 않도록 CSS inset 모드로 네이티브 네비게이션을 설정합니다:

import { NativeNavigation } from '@capgo/capacitor-native-navigation';

await NativeNavigation.configure({
  contentInsetMode: 'css',
  animationDuration: 360,
  glass: {
    effect: 'liquidGlass',
  },
});

Liquid Glass 탭 바를 렌더링합니다 (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}`);
});

앱 셸에 네이티브 페이지 전환을 추가합니다:

<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

In 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 처리하기

여러 중첩된 컴포넌트가 아닌, 단일 앱 셸(app shell)을 생성하여 그곳에 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를 사용하고, CSS(또는 Native Navigation의 contentInsetMode: 'css')가 safe area를 직접 제어하도록 설정하는 것이 좋습니다:

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: 'dist',
  ios: {
    contentInset: 'never',
  },
};

Capacitor의 자동 콘텐츠 인셋과 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 로 교체하세요. 많은 가로 overflow 문제는 100vw / w-screen, 중복된 safe-area padding, 또는 고정 너비 컨테이너 때문에 발생하며, viewport meta tag 자체의 문제는 아닙니다.

결론

Capacitor은 기존 웹 프로젝트를 기반으로 native applications를 구축하기 위한 훌륭한 선택지입니다. 여기에 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.를 사용하여 네이티브 기능을 구현하려면

Capacitor 앱용 Live updates

웹 레이어 버그가 라이브 상태라면, 앱 스토어 승인을 며칠씩 기다리지 말고 Capgo를 통해 수정 사항을 배포하세요. 네이티브 변경 사항은 정상 리뷰 절차를 그대로 따르는 반면, 사용자는 백그라운드에서 업데이트를 받습니다.

블로그 최신 글

Capgo는 정말 프로페셔널한 모바일 앱을 만드는 데 필요한 최고의 인사이트를 제공합니다.