본문 바로가기
튜토리얼

Pure React.js와 Capacitor로 모바일 앱 만들기

Capacitor를 사용하여 React.js 웹 애플리케이션을 네이티브 모바일 앱으로 변환하고, Capgo 네이티브 내비게이션, 트랜지션 및 iOS 레이아웃 베스트 프랙티스를 적용하는 가이드입니다.

Pure React.js와 Capacitor로 모바일 앱 만들기

이 튜토리얼에서는 React와 Capacitor를 사용해 모바일 애플리케이션을 만드는 과정을 안내합니다. 끝나면 Capacitor로 React.js 웹 앱을 네이티브 모바일 앱으로 변환하는 방법과 Capgo Native Navigation 및 Transitions로 네이티브 느낌을 더하는 방법을 알게 됩니다.

Capacitor를 사용하면 React.js 웹 앱을 네이티브 모바일 앱으로 쉽게 변환할 수 있으며, React Native 같은 새로운 방식을 배우거나 코드를 크게 수정할 필요가 없습니다.

과정은 몇 가지 간단한 단계로 이루어지며, 어느새 여러분의 React.js 앱은 완벽하게 작동하는 모바일 애플리케이션이 되어 있을 것입니다. 그럼 이 여정을 함께 시작해 보시죠.

Capacitor 개요

CapacitorJS는 게임 체인저입니다. 어떤 웹 프로젝트와도 매끄럽게 통합되고, 앱을 native webview로 감싸면서 Xcode와 Android Studio 프로젝트를 생성합니다. 또한 플러그인을 통해 JS bridge로 카메라 같은 native 디바이스 기능에 접근할 수 있습니다.

Capacitor를 사용하면 번거로운 과정이나 높은 학습 장벽 없이 native 모바일 앱을 간편하게 만들 수 있습니다. 간단한 API과 간결한 기능 덕분에 프로젝트에 쉽게 도입할 수 있습니다.

React.js 앱 설정하기

가장 간단한 방법으로 React 애플리케이션을 시작해 보겠습니다. npm 패키지 매니저로 새로운 React 앱을 생성합니다:

npx create-react-app my-app

프로젝트를 native 모바일 앱으로 변환하려면 앱의 내보내기 가 필요합니다.

이 부분은 잠시 후에 다시 다루겠습니다. 먼저 React 앱에 Capacitor를 통합하는 방법부터 알아보겠습니다.

React.js 앱에 Capacitor 통합하기

초기 설정 단계는 조금 복잡할 수 있지만, 그 이후에는 native 앱 래퍼 업데이트가 명령어 sync 명령어.

먼저 Capacitor CLI를 dev dependency로 설치하고 프로젝트에 설정하겠습니다. 설정 중 name과 bundle ID는 Enter 키를 눌러 기본값을 그대로 사용하세요.

다음으로, 코어 패키지와 iOS 및 Android 플랫폼에 필요한 관련 패키지를 설치합니다.

마지막으로 플랫폼을 추가하면, Capacitor가 프로젝트 루트에 각 플랫폼별 폴더를 생성합니다:

# Install the Capacitor CLI locally
npm install -D @capacitor/cli

# Initialize Capacitor in your React 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

이 iOS 및 Android 이제 React.js 프로젝트에 디렉토리가 생성되었습니다.

나중에 Android 프로젝트에 접근하려면 다음을 설치하세요: Android Studio. iOS의 경우 Mac이 필요하며 다음을 설치해야 합니다: iOS 프로파일링.

다음으로, 다음 파일을 webDir 에서 capacitor.config.json 아래와 같은 파일입니다:

{
  "appId": "com.example.app",
  "appName": "my-app",
  "webDir": "build",
  "bundledWebRuntime": false
}

빌드 명령어를 실행하고 Capacitor와 프로젝트를 동기화하세요:

npm run build
npx cap sync

이 npm run build 명령어를 통해 React.js 프로젝트를 빌드하며, npx cap sync 웹 code를 네이티브 플랫폼의 정확한 위치에 배치하여 앱에서 실행할 수 있도록 합니다.

이제 운이 좋고 에러가 없다면, React.js 앱을 기기에서 바로 실행할 준비가 끝났습니다!

네이티브 앱 빌드 및 배포

iOS 앱 개발에는 iOS 프로파일링, 그리고 Android 앱에는 Android Studio가 필요합니다. 앱을 앱 스토어에 배포하려면 iOS용 Apple Developer Program과 Android용 Google Play Console에 등록해야 합니다.

Capacitor CLI를 사용하면 두 네이티브 프로젝트를 여는 과정이 간편해집니다:

npx cap open ios
npx cap open android

네이티브 프로젝트 설정이 완료되면, 연결된 기기에 앱을 배포하는 과정은 매우 간단합니다.

Android Studio의 경우, 모든 로딩이 완료될 때까지 기다린 후 연결된 기기에 앱을 배포하세요.

Xcode의 경우, 시뮬레이터가 아닌 실제 기기에 앱을 배포하려면 Signing 계정을 설정해야 합니다. 설정 후 상단에서 연결된 기기를 선택하고 실행 버튼을 누르면 앱이 구동됩니다.

모든 과정이 성공적으로 끝났다면, React.js 웹 앱을 네이티브 모바일 애플리케이션으로 변환한 것입니다!

Capacitor Live Reload

최신 개발 프레임워크에는 보통 hot reload 기능이 포함되어 있으며, 다행히 Capacitor를 통해서도 동일한 기능을 모바일 기기에서!

사용할 수 있습니다. Capacitor 앱이 특정 URL에서 콘텐츠를 로드하도록 설정하면, 로컬에서 실행 중인 앱을 네트워크상의 모바일 기기에서 live reload로 확인할 수 있습니다.

먼저 로컬 IP 주소를 확인하세요. Mac에서는 터미널에 ipconfig getifaddr en0 를 입력하여 확인할 수 있습니다. Windows에서는 ipconfig 를 실행한 뒤 IPv4 주소를 찾으세요.

그다음, 명령어에 파라미터를 추가하여 Capacitor가 서버에서 앱을 직접 로드하도록 설정합니다. capacitor.config.ts 파일에 추가하세요:

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

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'build',
  bundledWebRuntime: false,
  server: {
    url: 'http://192.168.x.xx:3000',
    cleartext: true
  }
};

export default config;

정확한 IP와 포트를 사용해야 합니다. 이제 npx cap copy 를 실행하여 변경 사항을 native project에 적용하세요.

Android Studio나 Xcode를 통해 앱을 한 번 더 배포하고 나면, React 앱의 모든 변경 사항이 자동으로 리로드되어 앱에 즉시 반영됩니다!

단, 카메라와 같은 새로운 플러그인을 설치할 때는 native project를 다시 빌드해야 한다는 점에 유의하세요. 네이티브 파일이 변경되었기 때문에 실시간 업데이트(on the fly)로는 반영할 수 없습니다.

Capacitor 플러그인 사용법

그럼 Capacitor 플러그인을 어떻게 사용하는지 간단히 살펴보겠습니다. 우선 간단한 플러그인인 플러그인 공유하기, 그러면 네이티브 공유 창이 나타납니다:

npm i @capacitor/share

사용하려면 패키지를 import한 뒤 앱에서 해당 share() 함수를 호출하면 됩니다. 다음 App.js를 참고하세요.:

import { Share } from '@capacitor/share';

function ShareButton() {
  const share = async () => {
    await Share.share({
      title: 'React App',
      text: 'Visit this React App',
      url: 'http://localhost:3000',
      dialogTitle: 'Share with...'
    });
  };

  return (
    <button onClick={share}>
      Share
    </button>
  );
}

export default ShareButton;

새 플러그인을 설치한 후에는 반드시 다음 명령어로 React 프로젝트를 다시 sync해야 합니다: npx cap sync.

다음으로, Capgo 내비게이션과 트랜지션으로 iOS와 Android에서 앱을 더 네이티브하게 느끼게 하고, 가로 오버플로우나 세이프 에어리어가 잘리는 흔한 iOS 레이아웃 문제도 해결할 수 있습니다.

Capgo Native Navigation and Transitions로 만드는 네이티브한 UI

저는 수년간 Ionic 크로스 플랫폼 앱을 빌드할 때 사용하지만, 이미 사용 중인 환경이 있다면 React와 통합하는 방식은 다소 번거롭고 효율이 떨어질 수 있습니다. Tailwind CSS.

React + Capacitor 앱에서 네이티브 모바일 느낌을 구현하려면, Konsta UI 같은 웹 전용 UI 키트 대신 Capgo 플러그인을 사용하세요:

  • @capgo/capacitor-native-navigation — iOS에서는 native navbar와 Liquid Glass tab bar를, Android에서는 블러 처리된 tab bar 스타일을 제공합니다. React router는 라우트 상태를 유지하고, 플러그인이 native 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 }) => {
  navigate(`/${id}`);
});

앱 shell에 native page transitions를 추가하세요:

import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/react';

initTransitions({ platform: 'auto' });

export function AppShell() {
  const navigate = useNavigate();
  const outletRef = useRef<HTMLElement>(null);

  useEffect(() => {
    if (outletRef.current) {
      setupRouterOutlet(outletRef.current, { platform: 'auto', swipeGesture: 'auto' });
    }
  }, []);

  const openSettings = () => {
    setDirection('forward');
    navigate('/settings');
  };

  return <cap-router-outlet ref={outletRef}>{/* routes */}</cap-router-outlet>;
}

라우팅된 페이지를 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/index.css:

@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";

다음과 같은 유틸리티를 사용하세요: pt-safe, pb-safe, 그리고 px-safe 여기저기 흩뿌리는 대신 env(safe-area-inset-*) 직접 구축할 필요는 없습니다. 이 프로젝트는 활발히 개발 중이며, 만약 React 설정에 필요한 기능이 누락되어 있다면, 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,
#root {
  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: 'build',
  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를 사용하면 기존 웹 프로젝트를 기반으로 네이티브 앱을 매끄럽게 구축할 수 있으며, code를 공유하고 일관된 UI를 유지하는 간편한 방법을 제공합니다.

Capacitor와 같은 기술 덕분에 React.js 웹 앱으로 모바일 애플리케이션을 만드는 것이 그 어느 때보다 쉬워졌습니다. 멋진 네이티브 모바일 앱을 제작하여 웹 개발 기술을 한 단계 더 발전시켜 보세요. Happy coding!

앱 개발 프로세스를 가속화하는 방법에 대해 더 자세히 알아보려면, 무료 계정 가입하기 만들어 보세요.

Pure React.js와 Capacitor로 모바일 앱 만들기에서 계속하기

사용 중이라면 Pure React.js와 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 기능

Capacitor 앱용 Live updates

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

블로그 최신 글

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