메인 콘텐츠로 바로가기
튜토리얼

Capacitor 8을 사용하여 스캐치부터 시작하는 모바일-퍼스트 Vue 개발을 위한 Nuxt 모바일 앱을 빌드하세요.

Nuxt 4 프로젝트를 새로 만들고 Capacitor 8을 사용하여 iOS 및 Android 모바일 앱으로 변환하는 단계별 가이드.

마틴 도나디유

마틴 도나디유

콘텐츠 마케터

Capacitor 8을 사용하여 스캐치부터 시작하는 모바일-퍼스트 Vue 개발을 위한 Nuxt 모바일 앱을 빌드하세요.

소개

Nuxt를 사용하여 모바일 앱을 처음부터 처음으로 만들고 싶으십니까? 이 안내서에서는 모바일을 위해 처음부터 설정된 Nuxt 4 프로젝트를 만드는 방법을 안내합니다. 그리고 그 프로젝트를 Native iOS 및 Android 앱으로 패키징하는 방법을 알려드립니다. Capacitor 8.

이 튜토리얼을 마치면 시뮬레이터에서 작동하는 실제 모바일 앱을 만들 수 있으며, 계속 개발하고 앱 스토어와 구글 플레이에 게시할 수 있습니다.

소요 시간: ~30분

만드는 것:

  • 최신 디렉토리 구조를 갖춘 새로운 Nuxt 4 프로젝트
  • 모바일용 정적 생성 구성
  • Capacitor 8
  • 필수 플러그인
  • Native iOS 및 Android 앱

Already have a Nuxt app? Check out Nuxt 앱이 이미 있으신가요? 확인하세요. instead.

대신.

Prerequisites

  • 이러한 것을 설치하십시오. Make sure you have these installed: node --version)
  • Bun Node.js 18+curl -fsSL https://bun.sh/install | bash)
  • Node.js 18 이상이 설치되어야 합니다. (check with
  • __CAPGO_KEEP_0__를 확인하세요. (package manager (을 확인하세요. (Xcode (macOS only, for iOS development (Xcode (macOS 전용, iOS 개발을 위해 (Android Studio (Android Studio 안드로이드 개발을 위해

Step 1: 새로운 Nuxt 4 프로젝트 만들기

Nuxt 4 프로젝트를 시작하기 위해 새로운 프로젝트를 만드세요:

bunx nuxi@latest init my-mobile-app
cd my-mobile-app
bun install

Nuxt 4 디렉토리 구조

Nuxt 4는 app code이 포함된 새로운 디렉토리 구조를 사용합니다. app/ 디렉토리:

my-mobile-app/
  app/
    assets/
    components/
    composables/
    layouts/
    middleware/
    pages/
    plugins/
    utils/
    app.vue
  public/
  server/
  nuxt.config.ts
  package.json

이 구조는 앱과 서버 code 사이의 분리를 더 잘 제공합니다.

Step 2: 정적 생성을 위한 Nuxt 설정

Capacitor은 정적 HTML/JS/CSS 파일이 필요합니다. 정적 생성을 위한 Nuxt 설정을 하세요. nuxt.config.ts:

export default defineNuxtConfig({
  compatibilityDate: '2025-01-15',
  devtools: { enabled: true },

  // Enable static generation
  ssr: true,
  nitro: {
    preset: 'static',
  },
});

Step 3: 모바일 스크립트 추가

모바일 개발 스크립트를 추가하여 package.json __CAPGO_KEEP_0__

{
  "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"
  }
}

정적 생성을 테스트하세요:

bun run generate

정적 파일이 포함된 디렉토리를 볼 수 있어야 합니다. .output/public 4단계: __CAPGO_KEEP_0__ 8을 설치하세요.

Capacitor의 핵심 패키지를 설치하세요:

Install the Capacitor core packages:

bun add @capacitor/core
bun add -D @capacitor/cli

이러한 플러그인이 하는 일은?

bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences

@__CAPGO_KEEP_0__/app

  • @capacitor/app @__CAPGO_KEEP_0__/keyboard
  • @capacitor/keyboard @__CAPGO_KEEP_0__/splash-screen
  • capacitor core packages: — 네이티브 스플래시 화면 제어
  • @capacitor/status-bar — 장치 상태 바 스타일링
  • @capacitor/preferences — 키-값 저장소 (localStorage와 같은 네이티브 저장소)

Step 5: Capacitor 초기화

Capacitor을 프로젝트 세부 정보와 함께 초기화하세요.

bunx cap init "My Mobile App" com.example.mymobileapp --web-dir .output/public

Replace:

  • "My Mobile App" 앱의 표시 이름으로 대체
  • com.example.mymobileapp 앱 ID (역 도메인 표기법)으로 대체

이것은 capacitor.config.ts를 생성합니다. 플러그인 구성으로 업데이트하세요.

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile 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;

Step 6: 네이티브 플랫폼 추가

설치할 플랫폼 패키지를 설치합니다:

bun add @capacitor/ios @capacitor/android

네이티브 프로젝트를 생성합니다:

bunx cap add ios
bunx cap add android

This creates iosandroid 네이티브 프로젝트를 포함하는 디렉터리들을 생성합니다.

Step 7: 빌드 및 실행

프로젝트를 빌드하고 네이티브 플랫폼과 동기화하세요:

bun run mobile

iOS 시뮬레이터에서 열기:

bun run mobile:ios

또는 Android 에뮬레이터에서 열기:

bun run mobile:android

Xcode (iOS)에서:

  1. 디바이스 드롭다운에서 시뮬레이터를 선택하세요:
  2. Click the Play button or press Cmd + R

Android Studio에서:

  1. Gradle 동기화가 완료될 때까지 기다려 주세요
  2. 디바이스 드롭다운에서 에뮬레이터를 선택하세요
  3. Click the Run button or press Shift + F10

8단계: Live Reload 설정

개발을 위해 더 빠르게 하려면, 변경 사항이 즉시 디바이스에 나타나도록 Live Reload를 활성화하세요.

  1. 로컬 IP 주소를 찾으세요:
# macOS
ipconfig getifaddr en0

# Windows
ipconfig
  1. 개발 Capacitor 설정을 생성하세요. 업데이트 capacitor.config.ts:
import type { CapacitorConfig } from '@capacitor/cli';

const devConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  server: {
    url: 'http://YOUR_IP_ADDRESS:3000',
    cleartext: true,
  },
  plugins: {
    // ... same plugin config
  },
};

const prodConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  plugins: {
    // ... same plugin config
  },
};

const config = process.env.NODE_ENV === 'development' ? devConfig : prodConfig;

export default config;
  1. 개발 서버를 시작하고 config를 네이티브로 복사하세요:
bun run dev &
NODE_ENV=development bunx cap copy
  1. Xcode/Android Studio에서 다시 빌드하세요

Nuxt code의 편집 사항은 디바이스에서 즉시 반영됩니다.

9단계: 첫 번째 모바일 화면 만들기

모바일 화면을 만들려면, 홈 화면을 모바일 친화적으로 만들 수 있습니다. 업데이트 app/app.vue:

<template>
  <NuxtPage />
</template>

만들기 app/pages/index.vue:

<template>
  <main
    class="min-h-screen bg-linear-to-b from-green-500 to-green-700 flex flex-col items-center justify-center p-6 text-white"
  >
    <h1 class="text-4xl font-bold mb-4">My Mobile App</h1>
    <p class="text-xl mb-8 text-center opacity-90">
      Built with Nuxt 4 + Capacitor 8
    </p>

    <div v-if="appInfo" class="bg-white/20 rounded-lg p-4 backdrop-blur-sm mb-8">
      <p class="text-sm">
        {{ appInfo.name }} v{{ appInfo.version }}
      </p>
    </div>

    <div class="space-y-4 w-full max-w-sm">
      <button
        class="w-full py-4 px-6 bg-white text-green-600 rounded-xl font-semibold text-lg shadow-lg active:scale-95 transition-transform"
        @click="handleGetStarted"
      >
        Get Started
      </button>
      <button
        class="w-full py-4 px-6 bg-white/20 text-white rounded-xl font-semibold text-lg backdrop-blur-sm active:scale-95 transition-transform"
        @click="handleShare"
      >
        Share App
      </button>
    </div>
  </main>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { App } from '@capacitor/app';

const appInfo = ref<{ name: string; version: string } | null>(null);

let backButtonListener: { remove: () => void } | null = null;

onMounted(async () => {
  // Get app info
  try {
    appInfo.value = await App.getInfo();
  } catch (e) {
    // Web fallback
    appInfo.value = { name: 'My Mobile App', version: '1.0.0' };
  }

  // Handle Android back button
  backButtonListener = await App.addListener('backButton', ({ canGoBack }) => {
    if (!canGoBack) {
      App.exitApp();
    } else {
      window.history.back();
    }
  });
});

onUnmounted(() => {
  backButtonListener?.remove();
});

function handleGetStarted() {
  // Navigate to onboarding or main app
  console.log('Get started clicked');
}

async function handleShare() {
  // We'll implement this with the Share plugin later
  console.log('Share clicked');
}
</script>

10단계: Tailwind CSS 추가하기

스타일링이 작동하려면, 프로젝트에 Tailwind CSS를 추가해야 합니다.

bun add tailwindcss @tailwindcss/vite

업데이트 nuxt.config.ts:

import tailwindcss from '@tailwindcss/vite';

export default defineNuxtConfig({
  compatibilityDate: '2025-01-15',
  devtools: { enabled: true },

  ssr: true,
  nitro: {
    preset: 'static',
  },

  css: ['~/assets/css/main.css'],

  vite: {
    plugins: [tailwindcss()],
  },
});

만들기 app/assets/css/main.css:

@import 'tailwindcss';

:root {
  --sat: env(safe-area-inset-top);
  --sar: env(safe-area-inset-right);
  --sab: env(safe-area-inset-bottom);
  --sal: env(safe-area-inset-left);
}

body {
  padding-top: var(--sat);
  padding-right: var(--sar);
  padding-bottom: var(--sab);
  padding-left: var(--sal);
}

/* Prevent text selection on mobile */
* {
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Allow text selection in inputs */
input,
textarea {
  -webkit-user-select: auto;
  user-select: auto;
}

11단계: 공유 플러그인 추가하기

공유 버튼 기능을 구현하려면, 공유 플러그인을 구현합니다.

bun add @capacitor/share

공유 플러그인을 사용하려면: app/pages/index.vue Sync 및 재구축:

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { App } from '@capacitor/app';
import { Share } from '@capacitor/share';

// ... existing code ...

async function handleShare() {
  try {
    await Share.share({
      title: 'Check out this app!',
      text: 'Built with Nuxt 4 and Capacitor 8',
      url: 'https://capacitorjs.com',
      dialogTitle: 'Share with friends',
    });
  } catch (e) {
    console.log('Share cancelled or failed:', e);
  }
}
</script>

Sync 및 rebuild:

bun run mobile

프로젝트 구조

__CAPGO_KEEP_0__

my-mobile-app/
├── android/                  # Android native project
├── ios/                      # iOS native project
├── .output/
│   └── public/              # Static build output
├── app/
│   ├── assets/
│   │   └── css/
│   │       └── main.css
│   ├── pages/
│   │   └── index.vue
│   └── app.vue
├── capacitor.config.ts       # Capacitor configuration
├── nuxt.config.ts            # Nuxt configuration
├── package.json
└── ...

다음 단계

__CAPGO_KEEP_0__

필수 설정

  • 앱 아이콘: __CAPGO_KEEP_0__ ios/App/App/Assets.xcassets 기본 아이콘을 android/app/src/main/res
  • 스플래시 화면: __CAPGO_KEEP_0__ @capacitor/splash-screen 자연스럽게 프로젝트에서 사용하거나
  • __CAPGO_KEEP_0__ URL Scheme 설정을 위한 앱 구성

더 많은 기능 추가

  • 카메라: bun add @capacitor/camera
  • 위치 정보: bun add @capacitor/geolocation
  • 푸시 알림: bun add @capacitor/push-notifications 또는 @capgo/capacitor-firebase-messaging iOS 및 Android에서 Firebase Cloud Messaging을 위한
  • 파일 시스템: bun add @capacitor/filesystem

자연스러운 UI 및 전환

Capgo 플러그인을 사용하여 Konsta UI 대신 네이티브 모바일 경험을 얻으세요:

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

Tailwind의 안전 영역을 위해 추가하세요. @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

See Using @capgo/capacitor-native-navigation, Using @capgo/capacitor-transitions, 그리고 tailwind-capacitor Nuxt에 대한 특정 설정을 위한 레포입니다.

iOS 레이아웃 문제를 해결하는 방법 (뷰포트, 안전 영역, 가로 오버플로우)

iOS에서 콘텐츠가 잘려나가거나, 이동하거나, 수평으로 스크롤할 수 있는 경우, viewport 태그를 수정하거나 더 많은 콘텐츠를 추가하는 것만으로는 문제를 해결할 수 없습니다. 이러한 체크를 순서대로 진행하세요. overflow-x: hidden viewport meta 태그가 올바르게 적용되었는지 확인하세요.

viewport를

iOS safe area를 처리하는 데 한 번에 루트 wrapper만 사용하세요. nuxt.config.ts싱글 앱 셸을 생성하고 safe area 패딩을 거기에 적용하세요 — 여러 개의 중첩된 컴포넌트에 적용하지 마세요: app.head:

export default defineNuxtConfig({
  app: {
    head: {
      meta: [
        {
          name: 'viewport',
          content: 'width=device-width, initial-scale=1, viewport-fit=cover',
        },
      ],
    },
  },
});

모든 페이지 콘텐츠를

헤더, 모달, 레이아웃 wrapper에 중복된 safe-area 패딩을 적용하는 것은 UI가 잘려나가거나 너무 큰 것처럼 보이게 만듭니다.

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);
}

Tailwind CSS의 .app-shell@__CAPGO_KEEP_0__/tailwind-__CAPGO_KEEP_1__

와 같은 유틸리티를 사용하여 동일한 패딩을 표현할 수 있습니다. @capgo/tailwind-capacitoriOS safe area를 처리하는 데 한 번에 루트 wrapper만 사용하세요. pt-safe pb-safe px-safe on that single shell.

Capacitor iOS contentInset 을 설정하세요. never 첫 번째

In capacitor.config.ts, native inset을 비활성화하고 CSS (또는 Native Navigation의 contentInsetMode: 'css')가 safe area를 관리하도록 하세요.

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

Capacitor의 자동 콘텐츠 inset과 CSS env(safe-area-inset-*) padding을 혼합하는 것은 두 배의 간격이 발생하는 일반적인 원인입니다.

실제로 부여되는 요소를 찾으세요.

일반적으로 원인은 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안전 영역 패딩이 중복되거나 픽셀 너비 컨테이너에서 오는 경우입니다.

Over-the-Air 업데이트

설정 Capgo 앱 스토어 재제출 없이 업데이트를 푸시하기 위해:

bunx @capgo/cli init

문제 해결

빌드가 'Cannot find module'로 실패합니다. 실행하고 다시 시도해 보세요. bun install 및 다시 시도해 보세요.

iOS: “인증서를 찾을 수 없습니다” Xcode를 열고 Signing &amp; Capabilities로 이동하여 개발 팀을 선택하세요.

Android: “SDK 위치를 찾을 수 없습니다” 생성 android/local.propertiessdk.dir=/path/to/android/sdk

장치에 변경 사항이 보이지 않습니다 변경 사항이 적용된 후에 bun run mobile 변경 사항이 적용된 후에 장치에 변경 사항이 보이지 않으면,

live reload를 위해 IP 주소가 정확하고 개발 서버가 실행 중인지 확인하세요. .output/public이 비어 있거나 존재하지 않습니다. 확인하세요. nitro: { preset: 'static' } __CAPGO_KEEP_0__ nuxt.config.ts and bun run generate.

Resources

Capgo의 앱을 배달하기 위해 준비되셨나요? Capgo을 통해 업데이트를 더 빠르게 전달하는 방법을 알아보세요 — __CAPGO_KEEP_0__에 가입하세요. __CAPGO_KEEP_0__.

Build a Nuxt Mobile App from Scratch with Capacitor 8

__CAPGO_KEEP_0__를 사용 중이라면 Build a Nuxt Mobile App from Scratch with Capacitor 8 CI/CD 자동화 계획을 위해 연결하세요. Capgo CI/CD Capgo CI/CD에서 제품 워크플로우를 위해 Capgo Native Builds Capgo Native Builds에서 제품 워크플로우를 위해 Capgo Integrations Capgo Integrations에서 제품 워크플로우를 위해 CI/CD Integration CI/CD Integration의 구현 세부 사항을 위해 GitHub 액션 통합 GitHub 액션 통합 구현 세부 사항을 위해.

Capacitor 앱에 대한 실시간 업데이트

웹-layer 버그가 활성화된 경우 Capgo을 통해修정을 배포하는 대신 앱 스토어 승인까지 며칠 기다리지 마세요. 사용자는 배경에서 업데이트를 받으면서 네이티브 변경 사항은 일반적인 검토 경로에 남아 있습니다.

시작하기

최신 블로그

Capgo은 전문적인 모바일 앱을 만들기 위해 필요한 최고의洞察력을 제공합니다.