웹 앱을 App Store와 Google Play에 출시하려면, 빌드된 웹 앱을 Capacitor 기반의 native 프로젝트로 감싸고, 몇 가지 native 기능을 추가한 뒤, Apple 및 Google 개발자 계정을 생성하세요. 그 다음 iOS 및 Android 바이너리를 서명 및 빌드하고, 실제 사용자와 함께 테스트한 후, 스토어 등록 정보를 준비하여 심사를 제출하면 됩니다. 기존의 HTML, CSS, JavaScript는 native WebView 내에서 그대로 실행되므로 앱을 다시 작성할 필요가 없습니다.
대기 시간을 최소화할 수 있는 순서로 정리한 11단계 가이드입니다. Capacitor 8 명령어와 2026년 10월 기준 스토어 규정이 포함되어 있습니다.
준비 사항
- 정적 파일로 빌드되는 웹 앱 (React, Vue, Angular, Svelte, Next.js static export, Nuxt generate, 일반 HTML, 또는 Lovable이나 Bolt 같은 AI 빌더로 만든 앱).
- Node.js 22 이상 (Capacitor 8 요구 사항) 및 Bun 또는 기타 패키지 매니저.
- Android 빌드를 위한 Android Studio.
- iOS 빌드를 위한 macOS용 Xcode 26, 또는 Mac이 없는 경우 클라우드 빌드 서비스.
- Apple 연간 99 USD, Google 1회성 25 USD.
예상 소요 시간
| 단계 | 일반적인 소요 시간 | 병행 가능 여부 |
|---|---|---|
| 개발자 계정 등록 | 수 시간(개인) ~ 2주(신규 D-U-N-S 조직) | 네, 첫날부터 시작하세요 |
| Capacitor 설정 및 첫 기기 실행 | 1일 | |
| 모바일 최적화 및 네이티브 기능 구현 | 3일 ~ 3주 | |
| Signing 및 첫 빌드 | 1일 | |
| Google Play 비공개 테스트 (신규 개인 계정) | 최소 14일, 이후 프로덕션 액세스 검토 | 네, iOS TestFlight로 가능합니다 |
| 스토어 등록 정보 작성 | 1~2일 | 예 |
| 앱 심사 | Apple은 보통 1~2일, Google은 몇 시간에서 며칠이 소요됩니다 |
1단계: 오늘 바로 개발자 계정 등록 시작하기
계정 인증은 단축할 수 없는 단계이므로, 코딩을 시작하기 전에 미리 완료하세요.
- Apple Developer Program: 연간 99 USD. 개인은 2단계 인증이 설정된 Apple Account와 법적 실명이 필요합니다. 기업은 D-U-N-S 번호, 회사 웹사이트 및 해당 도메인의 업무용 이메일이 필요합니다.
- Google Play Console: 1회 25 USD. 기업은 D-U-N-S 번호가 필요하며, 신원 확인 절차가 진행될 수 있습니다.
Google Play에 개인으로 등록할 경우, 폐쇄형 테스트 규칙(9단계)이 적용됩니다. 전체 가이드: Apple 및 Google Play 개발자 계정 생성 방법.
2단계: 웹 앱을 모바일 환경에 맞게 준비하기
Capacitor는 앱을 WebView에서 실행합니다. 브라우저 탭에서는 괜찮지만, 앱에서는 어색하게 느껴지는 것들이 있습니다:
- 정적 빌드 결과물. Capacitor는 앱 번들에서 파일을 로드합니다. 휴대폰에서는 서버 사이드 렌더링(SSR)이 작동하지 않으므로, 프레임워크의 정적 출력물을 사용하세요 ("
next build와(과)output: 'export',nuxt generate, Vitebuild"). API의 API 호출은 이전과 동일하게 HTTPS를 통해 백엔드로 전달됩니다. - 파일 오리진 기반의 클라이언트 사이드 라우팅. History 라우팅을 사용하세요 (Capacitor가 앱을
https://localhost에서 서빙하며 Android와capacitor://localhost에서도 작동하므로, 딥 URL이index.html. - CORS. CORS를 확인하세요. API의 허용된 오리진(allowed origins)에 Capacitor 오리진을 추가하세요:
capacitor://localhost(iOS) 및https://localhost(Android). - 호버가 아닌 터치 방식. 호버 전용 메뉴를 제거하세요. 탭 대상 크기는 최소 44 x 44 포인트로 설정하세요.
- Safe area. 추가하세요
viewport-fit=coverviewport meta tag에 추가하고, 헤더와 하단 바에는 다음을 적용하여 여백을 확보하세요.env(safe-area-inset-top)및env(safe-area-inset-bottom). - 오프라인 및 느린 네트워크 환경. 빈 화면 대신 적절한 상태를 표시하세요. 리뷰어들은 불안정한 Wi-Fi 환경에서 테스트합니다.
- “앱을 다운로드하세요” 배너 금지 핵심 기능을 수행하기 위해 사용자를 웹사이트로 유도하는 링크도 금지됩니다.
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
3단계: Capacitor 추가하기
웹 프로젝트 루트 디렉토리에서:
bun add @capacitor/core
bun add -d @capacitor/cli
bunx cap init "My App" com.example.myapp --web-dir dist
bun add @capacitor/ios @capacitor/android
bun run build
bunx cap add ios
bunx cap add android
다음의 실제 출력 폴더를 사용하세요: --web-dir: dist Vite의 경우, out Next.js static export의 경우, .output/public Nuxt generate의 경우, build Create React App의 경우, dist/<project>/browser Angular의 경우.
Bundle ID ("com.example.myapp")는 앱이 스토어에 출시되면 변경할 수 없습니다. 소유 중인 역도메인을 사용하세요.
현재 capacitor.config.ts 구성은 다음과 같습니다:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'My App',
webDir: 'dist',
};
export default config;
Capacitor 8은 기본적으로 Swift Package Manager로 iOS 프로젝트를 생성하므로 CocoaPods가 필요 없습니다. 웹 code 변경 시마다:
bun run build
bunx cap sync
실행하세요:
bunx cap run ios
bunx cap run android
다음 폴더를 커밋하세요: ios/ 및 android/ 이 폴더들은 직접 수정할 소스 code입니다(권한, 아이콘, 서명). 더 자세한 내용은 다음을 참고하세요: Capacitor로 웹 앱을 모바일 앱으로 얼마나 쉽게 만들 수 있는지,AI 도구로 빌드했다면, 저희의 Lovable 모바일 전환 가이드.
4단계: 앱을 앱답게 만드는 네이티브 기능 추가
Apple 가이드라인 4.2(최소 기능)는 웹사이트에 껍데기만 씌운 앱을 거절합니다. 수십 개의 네이티브 기능이 필요한 건 아니지만, 앱은 앱답게 동작해야 합니다. 자주 쓰이는 유용한 추가 기능:
| 기능 | 플러그인 |
|---|---|
| 푸시 알림 | @capacitor/push-notifications |
| Google, Apple, Facebook 네이티브 로그인 | @capgo/capacitor-social-login |
| Face ID / 지문 인식 잠금 해제 | @capgo/capacitor-native-biometric |
| 카메라 및 사진 | @capacitor/camera |
| 인앱 결제 및 구독 | @capgo/capacitor-native-purchases |
| 네이티브 공유 시트 | @capacitor/share |
| 햅틱 피드백 | @capacitor/haptics |
| 상태 표시줄 및 스플래시 화면 | @capacitor/status-bar, @capacitor/splash-screen |
| 앱 평가 요청 prompt | @capgo/capacitor-in-app-review |
| Live Update | @capgo/capacitor-updater |
예시: “링크 복사” 버튼 대신 네이티브 공유 시트를 표시합니다.
import { Share } from '@capacitor/share';
import { Capacitor } from '@capacitor/core';
export async function shareLink(url: string, title: string) {
if (Capacitor.isNativePlatform()) {
await Share.share({ title, url });
} else {
await navigator.clipboard.writeText(url);
}
}
디지털 콘텐츠나 구독을 판매한다면 결제 방식을 미리 계획하세요. 대부분의 경우 Apple과 Google은 디지털 상품에 자체 인앱 결제 시스템을 요구합니다. 미국 App Store에서는 2025년 법원 판결 이후 앱이 외부 웹 결제로 연결될 수 있으며, 다른 지역은 자체 규칙이 있습니다. 실물 상품 및 서비스(배달, 차량 호출)는 Stripe 또는 어떤 결제 제공업체든 사용할 수 있습니다. 참고 Capacitor를 활용한 인앱 결제.
Capgo 플러그인 전체 카탈로그는 플러그인 페이지에서.
5단계: 아이콘, 스플래시 화면 및 권한 문자열
두 개의 소스 이미지만으로 모든 아이콘과 스플래시 크기를 생성하세요:
bun add -d @capacitor/assets
# assets/icon.png 1024x1024, assets/splash.png 2732x2732
bunx capacitor-assets generate
iOS에서는 사용하는 모든 권한에 대해 사용 목적을 ios/App/App/Info.plist에 명시해야 합니다. 그렇지 않으면 권한 요청 시 앱이 크래시되거나 Apple의 심사에서 거절됩니다:
<key>NSCameraUsageDescription</key>
<string>Take a photo of your receipt to attach it to an expense.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Choose receipt photos from your library.</string>
구체적인 이유를 작성하세요. “이 앱은 카메라가 필요합니다”와 같은 문구는 거절됩니다.
Android의 경우, 대부분의 플러그인이 manifest에 권한을 직접 추가합니다. 사용하지 않는 권한은 제거하세요. Google은 민감한 권한에 대해 정당한 사유를 요구합니다.
또한 다음을 추가하세요: privacy manifest를 (PrivacyInfo.xcprivacy) code에서 required-reason API를 사용하는 경우, 다음을 확인하세요. iOS 앱을 위한 privacy manifest 가이드.
6단계: Signing 설정
iOS. Apple Distribution certificate(및 해당 private key, 보통 다음 형식으로 내보내기)와 .p12bundle ID에 맞는 App Store Connect provisioning profile이 필요합니다. Xcode를 통해 자동으로 생성하거나, Mac 없이도 직접 생성할 수 있습니다. 자세한 내용은 iOS certificate 및 provisioning profile 설명를 iOS 인증서 생성기 를 통해 브라우저에서 CSR 단계를 처리할 수 있습니다.
Android. upload용 keystore를 생성하고 반드시 백업해 두세요. Google Play는 Play App Signing을 사용하므로, 최종 앱 signing key는 Google이 보유하며 사용자는 본인의 키로 upload를 진행합니다.
keytool -genkeypair -v -keystore upload-keystore.jks -alias upload \
-keyalg RSA -keysize 2048 -validity 10000
또는 다음을 사용하세요 Android keystore 생성기.
7단계: 릴리스 바이너리 빌드
로컬에서
iOS (2026년 4월부터 App Store 업로드에 필수인 Xcode 26이 설치된 Mac 사용):
bunx cap open ios- 다음 항목을 App 타겟으로 선택하고, 버전과 빌드 번호를 설정한 뒤, Signing & Capabilities에서 팀을 선택하세요.
- 다음 항목을 선택하세요: 모든 iOS 기기 (arm64), 그런 다음 Product > Archive.
- Organizer에서, Distribute App > App Store Connect > Upload.
Android:
bun run build
bunx cap sync android
cd android
./gradlew bundleRelease
AAB 파일 위치: android/app/build/outputs/bundle/release/. 구성하세요 signingConfigs 에서 android/app/build.gradle keystore를 사용하며, 환경 변수에서 비밀번호를 불러옵니다.
반드시 targetSdkVersion 버전은 36입니다. 2026년 8월 31일부터 Google Play는 신규 앱 및 업데이트에 Android 16 (API 36) 타겟팅을 요구하며, 이는 Capacitor 8 기본값입니다.
클라우드에서
Mac이 없거나 CI를 통해 재현 가능한 빌드를 원하는 경우, Capgo 빌드 호스팅된 머신에서 양쪽 플랫폼을 모두 빌드하며, TestFlight 및 Google Play로 직접 upload할 수 있습니다:
bunx @capgo/cli@latest build credentials save --appId com.example.myapp --platform ios
bunx @capgo/cli@latest build credentials save --appId com.example.myapp --platform android
bunx @capgo/cli@latest build request com.example.myapp --platform ios --path .
bunx @capgo/cli@latest build request com.example.myapp --platform android --path .
인증 정보는 빌드 용도로만 사용되며 Capgo 서버에 저장되지 않습니다. 다음을 참조하세요: Capgo Build 문서.
8단계: 테스터에게 배포하기
Apple이나 Google 검토관이 확인하기 전에 실제 기기에 빌드를 설치하여 테스트하세요.
- iOS: TestFlight로 upload합니다. 내부 테스터(팀원 최대 100명)는 프로세싱 직후 바로 받을 수 있으며, 외부 테스터(최대 10,000명)는 짧은 Beta App Review를 거친 후 받을 수 있습니다.
- Android: Play Console에서 내부 테스트 릴리스를 생성하고 참여 링크를 공유합니다.
회원가입 및 로그인, 샌드박스 결제, 푸시 알림, 오프라인 동작, 키보드가 입력창을 가리는 문제, Android의 뒤로 가기 버튼 동작 등을 테스트하세요. 각 옵션별 상세 내용은 다음과 같습니다: iOS 및 Android 앱을 테스터에게 배포하는 방법.
9단계: Google Play 비공개 테스트 실행 (신규 개인 계정)
2023년 11월 13일 이후에 생성된 개인 Play 계정이라면, 프로덕션에 게시할 수 없습니다. 최소 12명의 테스터가 참여를 선택한 상태로 14일 연속 진행하는 비공개 테스트를 완료해야 합니다.. 그런 다음 Play Console dashboard에서 프로덕션 액세스를 신청하세요. Google은 보통 일주일 이내에 검토합니다.
사용 가능한 Android build가 준비되는 즉시 이 과정을 시작하세요. 테스터가 직접 참여할 수 있도록 Google Group을 테스터 목록으로 사용하세요. 14일 동안 업데이트를 배포하고 피드백을 수집하세요. Google이 무엇을 배웠는지 묻기 때문입니다. 조직 계정은 예외입니다.
10단계: 스토어 등록 정보 준비 및 제출
두 스토어 모두 앱 이름, 설명, 허용된 크기의 스크린샷, 아이콘, 개인정보 처리방침 URL, 개인정보 공개(Apple App Privacy 및 Google Data safety), 연령 등급 설문, 지원 연락처, 앱에 로그인이 있으면 데모 계정이 필요합니다. Google은 1024 x 500 feature graphic도 필요합니다. 사양 및 제한: App Store 및 Google Play 등록 정보 준비 방법.
iOS 제출 방법: App Store Connect에서 버전을 생성하고, TestFlight build를 선택한 뒤, App Review Information(데모 계정, 메모)을 입력한 다음 클릭하고 심사용으로 추가, 그런 다음 제출.
Android 제출 방법: AAB로 프로덕션 릴리스를 생성하거나(또는 테스트 트랙에서 검증된 버전을 승격), 모든 앱 콘텐츠 선언을 완료하고, 국가를 설정한 뒤 심사를 요청하세요.
웹 앱이 가장 자주 겪는 거절 사유:
- 4.2 최소 기능 미달: 앱이 단순한 웹사이트인 경우입니다. 네이티브 기능을 추가하고 브라우저 같은 UI를 제거하세요.
- 로그인이 필요하지만 데모 계정이 없음, 또는 계정이 작동하지 않는 경우입니다.
- 개인정보 보호 중심의 로그인 옵션 부재 iOS에서 Google 또는 Facebook 로그인을 제공할 때 발생합니다. 가이드라인 4.8에 따라 데이터 수집을 제한하는 동등한 옵션이 필요하며, 보통 Sign in with Apple을 사용합니다.
- 계정 삭제 기능 없음 앱 내에서 사용자가 계정을 만들 수 있는 경우.
- Stripe를 통한 디지털 결제 인앱 결제가 필수인 경우.
- iPad 레이아웃 깨짐 현상 프로젝트가 기본적으로 iPad를 지원하기 때문입니다.
- 권한 요청 문구가 없거나 모호함.
저희 첫 앱 심사 가이드 및 iOS 앱 제출 가이드 각 항목을 자세히 살펴보겠습니다.
11단계: 심사 대기 없이 업데이트 배포하기
출시 후 대부분의 변경 사항은 여전히 웹 code에 남게 됩니다. 매번 수정을 위해 스토어 빌드를 새로 하는 대신, Live Update를 추가하세요. Capgo updater는 Capgo에서 새로운 웹 번들을 다운로드하여 다음 실행 시 적용하며, 새 번들이 시작되지 않을 경우 자동으로 롤백합니다.
bun add @capgo/capacitor-updater
bunx cap sync
bunx @capgo/cli@latest init
호출 notifyAppReady() 앱이 시작된 후 호출하여 updater가 번들의 상태가 정상임을 알 수 있도록 합니다:
import { CapacitorUpdater } from '@capgo/capacitor-updater';
CapacitorUpdater.notifyAppReady();
이제 웹 code의 각 릴리스는 명령어 하나로 가능합니다:
bun run build
bunx @capgo/cli@latest bundle upload --channel production
두 스토어 모두 업데이트가 앱의 주요 목적을 변경하거나 결제 규칙을 우회하지 않는 한, 인터프리터 방식의 code에 대해 이를 허용합니다. Native 변경 사항(새 플러그인, 새 권한, Capacitor 업그레이드)은 여전히 스토어를 거쳐야 합니다. 자세한 내용은 Capgo Live Update 사용하기 및 updater 문서.
첫 스토어 제출 전에 플러그인을 추가하세요. 사용자가 설치하는 바이너리에 포함되어 있어야 하며, 그렇지 않으면 첫 번째 live update는 두 번째 스토어 릴리스가 나온 후에야 사용자에게 도달할 수 있습니다.
마지막으로 자동화하세요: GitHub Actions 또는 GitLab CI에서 태그가 생성될 때마다 빌드 및 upload를 수행하고, GitHub로 머지될 때마다 Live Update를 푸시하세요. main, 그리고 Native 변경 사항은 Native 릴리스를 유지하세요.
출시 전 체크리스트
- Apple 및 Google 계정 승인 및 약관 동의 완료
- 오프라인 작동 또는 명확한 오프라인 상태 표시
- Safe area, 키보드 및 Android 뒤로 가기 버튼 대응
- 웹사이트에서 제공할 수 없는 네이티브 기능 포함
- 아이콘, 스플래시, 권한 문자열, 개인정보 보호 매니페스트
- 배포 인증서, App Store 프로필, 업로드용 keystore 백업
- Android는 SDK 36 타겟, iOS는 Xcode 26 빌드
- 실제 기기에서 TestFlight 및 Play 내부 테스트 완료
- Google Play 비공개 테스트 완료 (개인 계정)
- 양대 스토어 스토어 등록 완료 및 데모 계정 추가
- 사용자 가입 기능이 있는 경우 앱 내 계정 삭제 기능
- 첫 번째 바이너리에 Live Update 플러그인 포함
문제 해결
실행 시 흰 화면이 나타남. webDir 잘못된 폴더를 가리키거나 잊어버린 경우 bunx cap sync 빌드 후 확인하세요. 다음을 ios/App/App/public 및 android/app/src/main/assets/public 포함되어 있는지 index.html.
앱에서만 API 호출이 실패함. CORS: 허용 capacitor://localhost 및 https://localhost. 또한 다음을 호출하고 있지 않은지 확인하세요 http:// URL은 iOS에서 기본적으로 차단됩니다.
새로고침 또는 딥 링크 시 404 라우트 오류. 대체 수단으로 사용할 라우터를 사용하거나 index.html, 또는 이전 설정을 위해 hash routing을 사용하세요.
Xcode signing 오류. 다음에서 오류 목록을 확인하세요: iOS 인증서 및 프로비저닝 프로파일 설명.
업그레이드 후 Gradle build 실패. Capacitor 8을 사용하려면 Capacitor에 나열된 대로 Android Studio Otter (2025.2.1) 이상 버전과 JDK 21이 필요합니다. Capacitor 8 업그레이드 가이드. 기타 Gradle 오류는 다음을 참조하세요: Capacitor에서 Android build 오류를 해결하는 방법.
대상 SDK에 대한 Google Play upload 거부. 설정 targetSdkVersion = 36 에서 android/variables.gradle.