Skip to main content
강의

Next.js 모바일 앱을 처음부터 Capacitor 8로 만들기

Next.js 15 프로젝트를 새로 만들고 Capacitor 8를 사용하여 iOS 및 Android 모바일 앱으로 변환하는 단계별 가이드입니다. 모바일 개발을 처음부터 시작하는 데 이상적입니다.

마틴 도나디우

마틴 도나디우

콘텐츠 마케터

Next.js 모바일 앱을 처음부터 Capacitor 8로 만들기

소개

Next.js로 모바일 앱을 처음부터 만들고 싶으신가요? 이 가이드는 모바일 앱을 처음부터 만들기 위해 Next.js 15 프로젝트를 새로 만들고, 모바일 앱을 처음부터 만들기 위해 __CAPGO_KEEP_0__ 8를 사용하여 iOS 및 Android 앱으로 패키징하는 단계별 가이드입니다. Capacitor 8.

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

시간 소요량: ~30분

제작할 프로젝트:

  • 새로운 Next.js 15 프로젝트 (App Router)
  • 모바일을 위한 정적 내보내기 구성
  • Capacitor 8 (기본 플러그인)
  • iOS 및 Android 네이티브 앱
  • 라이브 리로드 개발 환경

Next.js 앱이 이미 있으신가요? Next.js 앱을 모바일로 변환하는 방법 대신 확인하세요.

사전 요구 사항

이것들을 설치했는지 확인하세요:

  • Node.js 18+ (__CAPGO_KEEP_0__ node --version)
  • Bun Xcodecurl -fsSL https://bun.sh/install | bash)
  • (macOS 전용, iOS 개발을 위해) Android Studio
  • (Android 개발을 위해) 1단계: 새로운 Next.js 프로젝트 만들기

새로운 Next.js 15 프로젝트를 시작하세요:

입력받을 때 다음 옵션을 선택하세요:

bunx create-next-app@latest my-mobile-app

__CAPGO_KEEP_0__

  • TypeScript: Yes (recommended)
  • ESLint: Yes
  • Tailwind CSS: Yes (recommended for mobile styling)
  • src/ directory: Yes
  • App Router: Yes (recommended)
  • Import alias: Default (@/*)

프로젝트로 이동하세요:

cd my-mobile-app

2단계: Next.js를 정적 내보내기 위해 구성하세요.

Capacitor는 정적 HTML/JS/CSS 파일이 필요합니다. Next.js를 정적 내보내기 위해 구성하려면 next.config.ts:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  output: 'export',
  images: {
    unoptimized: true,
  },
  // Ensure trailing slashes for proper routing in Capacitor
  trailingSlash: true,
};

export default nextConfig;

이러한 설정을 왜 사용하는지 알아보세요.

  • output: 'export' — 정적 HTML을 생성하여 Node.js 서버가 필요하지 않도록 합니다.
  • images: { unoptimized: true } — Next.js 이미지 최적화를 비활성화합니다 (서버가 필요합니다)
  • trailingSlash: true — 네이티브 WebView에서 올바른 라우팅을 보장합니다.

3단계: 모바일 스크립트 추가

모바일 개발 스크립트를 업데이트하세요: package.json 빌드 테스트:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "mobile": "bun run build && bunx cap sync",
    "mobile:ios": "bun run mobile && bunx cap open ios",
    "mobile:android": "bun run mobile && bunx cap open android"
  }
}

빌드가 정상적으로 작동하는지 확인하세요:

bun run build

결과를 확인하세요: out 정적 파일이 있는 디렉토리입니다.

4단계: Capacitor 8을 설치합니다.

Capacitor의 핵심 패키지를 설치합니다:

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

대부분의 모바일 앱이 필요로 하는 필수 플러그인을 설치합니다:

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

이러한 플러그인이 무엇을 하는지 설명합니다:

  • @capacitor/app — 앱의 라이프사이클 이벤트 (전경/후경, 깊이 링크)
  • @capacitor/keyboard — 키보드 동작을 제어합니다.
  • @capacitor/splash-screen — 네이티브 스플래시 스크린을 제어합니다.
  • @capacitor/status-bar — 기기 상태 바 스타일링
  • @capacitor/preferences — 키-값 저장소 (localStorage와 같은 네이티브)

5단계: Capacitor 초기화

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

bunx cap init "My Mobile App" com.example.mymobileapp --web-dir out

대체:

  • "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: 'out',
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      launchAutoHide: true,
      androidScaleType: 'CENTER_CROP',
      splashFullScreen: true,
      splashImmersive: true,
    },
    Keyboard: {
      resize: 'body',
      resizeOnFullScreen: true,
    },
    StatusBar: {
      style: 'light',
    },
  },
};

export default config;

6단계: 네이티브 플랫폼 추가

플랫폼 패키지를 설치하세요:

bun add @capacitor/ios @capacitor/android

자연 프로젝트를 생성하세요:

bunx cap add ios
bunx cap add android

이것은 iosandroid 자연 프로젝트가 포함된 디렉토리를 생성합니다.

7단계: 빌드 및 실행

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

bun run mobile

iOS 시뮬레이터에서 열기:

bun run mobile:ios

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

bun run mobile:android

Xcode (iOS)에서:

  1. 디바이스 드롭다운에서 시뮬레이터를 선택하세요
  2. Play 버튼을 클릭하거나 Cmd + R

Android Studio에서:

  1. Gradle 동기화가 완료될 때까지 기다려 주세요.
  2. 디바이스 드롭다운에서 에뮬레이터를 선택하세요.
  3. Run 버튼을 클릭하거나 Shift + F10

8단계: Live Reload 설정

빠른 개발을 위해 Live Reload를 활성화하여 변경 사항이 즉시 장치에 나타나도록 하세요.

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

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

const devConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: 'out',
  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: 'out',
  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에서 다시 빌드하세요

이제 Next.js code의 편집 사항이 장치에서 즉시 반영됩니다.

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

간단한 모바일 친화적인 홈 화면을 만들겠습니다. Update src/app/page.tsx:

'use client';

import { useEffect, useState } from 'react';
import { App } from '@capacitor/app';
import { Keyboard } from '@capacitor/keyboard';

export default function Home() {
  const [appInfo, setAppInfo] = useState<{ name: string; version: string } | null>(null);

  useEffect(() => {
    // Get app info on mount
    App.getInfo().then(setAppInfo).catch(console.error);

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

    // Hide keyboard when tapping outside inputs
    const keyboardHandler = Keyboard.addListener('keyboardWillShow', () => {
      document.body.classList.add('keyboard-open');
    });

    return () => {
      backHandler.then(h => h.remove());
      keyboardHandler.then(h => h.remove());
    };
  }, []);

  return (
    <main className="min-h-screen bg-linear-to-b from-blue-500 to-blue-700 flex flex-col items-center justify-center p-6 text-white">
      <h1 className="text-4xl font-bold mb-4">My Mobile App</h1>
      <p className="text-xl mb-8 text-center opacity-90">
        Built with Next.js 15 + Capacitor 8
      </p>

      {appInfo && (
        <div className="bg-white/20 rounded-lg p-4 backdrop-blur-sm">
          <p className="text-sm">
            {appInfo.name} v{appInfo.version}
          </p>
        </div>
      )}

      <div className="mt-12 space-y-4 w-full max-w-sm">
        <button className="w-full py-4 px-6 bg-white text-blue-600 rounded-xl font-semibold text-lg shadow-lg active:scale-95 transition-transform">
          Get Started
        </button>
        <button className="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">
          Learn More
        </button>
      </div>
    </main>
  );
}

Step 10: notch 영역 처리 추가

모바일 기기는 notch, 홈 인디케이터, 상태바를 가지고 있습니다. Tailwind를 사용하여 notch 영역 처리를 추가하세요.

업데이트 src/app/globals.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

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

/* Keyboard handling */
.keyboard-open {
  --sab: 0px;
}

프로젝트 구조

프로젝트 구조는 다음과 같이 되어야 합니다.

my-mobile-app/
├── android/              # Android native project
├── ios/                  # iOS native project
├── out/                  # Static build output
├── src/
│   ├── app/
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── ...
├── capacitor.config.ts   # Capacitor configuration
├── next.config.ts        # Next.js configuration
├── package.json
└── ...

다음 단계

역할: Capgo Builder / 네이티브 클라우드 빌드 제품 페이지. 역할: 짧은 UI 레이블 또는 네비게이션 아이템. 메시지 키 `native_build_builder_credit_next` (네이티브 빌드 빌더 크레딧 넥스트).

이제 Next.js 모바일 앱이 작동합니다. 다음 단계는 다음과 같습니다.

  • 필수 설정 앱 아이콘: ios/App/App/Assets.xcassets 기본 아이콘을 android/app/src/main/res
  • 역할: Capgo 마케팅 웹사이트. 역할: 짧은 UI 레이블 또는 네비게이션 아이템. 페이지: trust.astro. 메시지 키 `and` (그리고). 자체 프로젝트에서 커스터마이즈하거나 사용 @capacitor/splash-screen 설정
  • 깊이 있는 링크: 앱의 URL 스키마를 구성

더 많은 기능 추가

  • 카메라: bun add @capacitor/camera
  • 위치 정보: bun add @capacitor/geolocation
  • 푸시 알림: bun add @capacitor/push-notifications
  • 파일 시스템: bun add @capacitor/filesystem

자연스러운 UI 및 전환

Capgo 플러그인 대신 Konsta UI를 사용하지 않고 자체 모바일 느낌을 위해:

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

Tailwind safe areas를 위해 추가하세요 @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

See Using @capgo/capacitor-native-navigation, Using @capgo/capacitor-transitions, 그리고 tailwind-capacitor Next.js에 특정한 설정을 위한

뷰포트, Safe Area, 그리고 수평 오버플로우를 해결하는 iOS 레이아웃 문제

iOS에서 콘텐츠가 잘려나가거나, 이동된 것처럼 보인다면, 더 많은 overflow-x: hidden 또는 뷰포트 태그를 조정하는 것만으로 문제를 해결할 수 없다. 이러한 체크를 순서대로 진행하라.

뷰포트 메타 태그가 올바르게 적용되었는지 확인하라.

App Router (app/export) viewport from app/layout.tsx:

import type { Viewport } from 'next';

export const viewport: Viewport = {
  width: 'device-width',
  initialScale: 1,
  viewportFit: 'cover',
};

Pages Router (pages/) put the viewport meta tag in pages/_app.tsx, not _document.tsx.

iOS safe area를 한 루트 wrapper에서만 처리하라.

단일 앱 셸을 생성하고 안전 영역 패딩을 적용하라 — 여러 개의 중첩된 컴포넌트에서만:

html,
body,
#__next {
  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);
}

모든 페이지 콘텐츠를 wrapper 내에 감싸라. .app-shell. 중복된 안전 영역 패딩이 헤더, 모달, 레이아웃 wrapper에 종종 UI가 잘린 것처럼 보이거나 너무 크게 보이게 만듭니다.

With @capgo/tailwind-capacitor, __CAPGO_KEEP_0__의 유용한 유틸리티를 사용하여 단일 셸에 패딩을 표현할 수 있습니다. pt-safe pb-safe px-safe Set __CAPGO_KEEP_0__ iOS

Set Capacitor iOS contentInset first never In

, 원래의 안전 영역을 CSS (또는 Native Navigation의 )가 관리하도록 native inset을 비활성화하고 CSS가 안전 영역을 관리하도록 합니다. capacitor.config.tsMixing __CAPGO_KEEP_0__’s automatic content inset with CSS contentInsetMode: 'css'live_update_dynamic_label_to

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

Mixing Capacitor’s automatic content inset with CSS env(safe-area-inset-*) padding은 일반적인 두 줄 간격의 원인입니다.

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

일반적으로 원인 요소는 100vwTailwind 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, 중복된 안전 영역 패딩 또는 고정 너비 컨테이너 — viewport meta 태그 자체가 아닌 것에서 오는 것입니다.

Over-the-Air 업데이트

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

bunx @capgo/cli init

문제 해결

빌드 실패: '모듈을 찾을 수 없음' 실행 bun install 다시 시도해 보세요.

iOS: '인증서를 찾을 수 없음' Xcode를 열고, Signing &amp; Capabilities로 이동하여 개발 팀을 선택하세요.

Android: 'SDK' 위치를 찾을 수 없음 생성 android/local.propertiessdk.dir=/path/to/android/sdk

디바이스에 나타나지 않는 변경 사항 변경 사항이 적용된 것을 확인하세요. bun run mobile live reload를 위해 IP 주소가 정확하고 개발 서버가 실행 중인지 확인하세요.

자원

앱을 배달할 준비가 되셨나요? Capgo이 업데이트를 더 빠르게 전달하는 방법에 대해 배워보세요 — 무료 계정으로 가입하세요. 오늘

Next.js 모바일 앱을 Capacitor 8부터 다시 시작하세요.

만약 __CAPGO_KEEP_0__ 8을 사용 중이라면 Next.js 모바일 앱을 Capacitor 8부터 다시 시작하세요. __CAPGO_KEEP_0__ 8과 CI/CD 자동화 계획을 연결하세요. Capgo CI/CD Capgo CI/CD에서 제품 워크플로우 Capgo Native Builds Capgo Native Builds에서 제품 워크플로우 Capgo Integrations Capgo Integrations에서 제품 워크플로우 CI/CD 통합 CI/CD 통합 구현 세부 사항 GitHub 액션 통합 GitHub 액션 통합 구현 세부 사항

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

웹-layer 버그가 실시간으로 발생하면 Capgo를 통해 픽스를 배포하세요. 앱 스토어 승인 대기 없이 사용자가 배경에서 업데이트를 받으며 네이티브 변경은 일반적인 검토 경로를 유지합니다.

마틴의 인간 지원

시작하기

최신 블로그

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