웹 앱을 App Store와 Google Play에 출시하려면, 빌드된 웹 앱을 Capacitor로 네이티브 프로젝트에 래핑하고 몇 가지 네이티브 기능을 추가하세요. Apple과 Google 개발자 계정을 생성하고, iOS 및 Android 바이너리를 서명 및 빌드한 후 실제 사용자와 테스트합니다. 스토어 리스팅을 준비하고 심사에 제출하면 됩니다. 기존 HTML, CSS, JavaScript는 네이티브 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 빌드용 Xcode 26(macOS), 또는 Mac이 없으면 클라우드 빌드 서비스.
- Apple은 연간 99 USD, Google은 1회 25 USD.
예상 타임라인
| 단계 | 일반적인 소요 시간 | 병렬 진행 가능? |
|---|---|---|
| 개발자 계정 등록 | 개인은 몇 시간, 신규 D-U-N-S가 필요한 조직은 최대 2주 | 네, 첫날부터 시작하세요 |
| Capacitor 설정 및 첫 기기 실행 | 1일 | |
| 모바일 최적화 및 네이티브 기능 | 3일 ~ 3주 | |
| 서명 및 첫 빌드 | 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는 앱 번들에서 파일을 로드합니다. 서버 사이드 렌더링은 폰에서 실행되지 않습니다. 프레임워크의 정적 출력(
next build포함output: 'export',nuxt generate, Vitebuild). API 호출은 이전과 마찬가지로 HTTPS를 통해 백엔드로 전달됩니다. - 파일 오리진에서 동작하는 클라이언트 사이드 라우팅. history 라우팅을 사용하세요 (Capacitor는 앱을 서빙합니다:
https://localhostAndroid에서는, 그리고capacitor://localhostiOS에서 작동하도록) 설정하고, 딥 URL이 다음으로 폴백되는지 확인하세요index.html. - CORS. API의 허용 origin에 Capacitor origin을 추가하세요:
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에서는 사용하는 모든 권한에 대해 Info.plist에 사용 목적 설명을 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단계: 서명 설정
iOS. Apple Distribution 인증서(개인 키 포함, 보통 다음 형식으로 내보냄 .p12)와 bundle ID에 맞는 App Store Connect provisioning profile이 필요합니다. Xcode에서 자동으로 생성하거나, Mac 없이도 직접 생성할 수 있습니다. 자세한 내용은 iOS 인증서 및 provisioning profile 설명; iOS 인증서 생성기 에서 브라우저를 통해 CSR 단계를 처리합니다.
Android. upload용 keystore를 생성하고 반드시 백업해 두세요. Google Play는 Play App Signing을 사용하므로 최종 앱 서명 키는 Google이 보관하고, 사용자는 본인 키로 upload에 서명합니다.
keytool -genkeypair -v -keystore upload-keystore.jks -alias upload \
-keyalg RSA -keysize 2048 -validity 10000
또는 다음을 사용하세요 Android 키스토어 생성기.
7단계: 릴리스 바이너리 빌드
로컬
iOS (Xcode 26이 설치된 Mac에서, 2026년 4월부터 App Store 업로드에 필수):
bunx cap open ios- 다음을 선택하세요: 앱 target을 선택하고 버전 및 빌드 번호를 설정한 뒤, 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에 직접 업로드할 수 있습니다:
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에 업로드합니다. 내부 테스터(최대 100명)는 처리 직후, 외부 테스터(최대 10,000명)는 짧은 Beta App Review 후 받을 수 있습니다.
- Android: Play Console에서 내부 테스트 릴리스를 생성하고 opt-in 링크를 공유합니다.
회원가입과 로그인, 샌드박스 결제, 푸시 알림, 오프라인 동작, 키보드가 입력창을 가리는지, 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 정보(데모 계정, 메모)를 입력하고 다음을 클릭하세요: 심사를 위해 추가, 그 다음 제출.
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에 대해 이를 허용합니다. 네이티브 변경 사항(새 플러그인, 새 권한, Capacitor 업그레이드)은 여전히 스토어를 거쳐야 합니다. 자세한 내용은 Capgo Live Update 사용하기 및 updater 문서.
첫 스토어 제출 전에 플러그인을 추가하세요. 사용자가 설치하는 바이너리에 포함되어 있어야 하며, 그렇지 않으면 첫 번째 live update는 두 번째 스토어 릴리스가 완료된 후에야 사용자에게 도달할 수 있습니다.
마지막으로 자동화하세요: GitHub Actions 또는 GitLab CI에서 태그마다 빌드 및 업로드하고, 머지될 때마다 Live Update를 푸시하세요 main, 네이티브 변경 사항은 네이티브 릴리스로 처리하세요.
출시 전 체크리스트
- Apple 및 Google 계정 승인, 약관 동의 완료
- 앱이 오프라인에서 작동하거나 명확한 오프라인 상태를 표시
- Safe areas, 키보드, Android 백 버튼 처리
- 웹사이트로는 제공할 수 없는 네이티브 기능 몇 가지
- 아이콘, 스플래시, 권한 문자열, 개인정보 처리방침 매니페스트
- 배포 인증서, App Store 프로필, 업로드 키스토어 백업
- Android는 SDK 36, iOS는 Xcode 26으로 빌드
- 실제 기기에서 TestFlight 및 Play 내부 테스트 완료
- Google Play 폐쇄 테스트 완료 (개인 계정)
- 양쪽 스토어 리스팅 완료, 데모 계정 추가
- 가입 기능이 있는 경우 앱 내 계정 삭제
- 첫 번째 바이너리에 Live Updates 플러그인 포함
문제 해결
시작 시 흰 화면. webDir 잘못된 폴더를 가리키거나 빠뜨린 경우 bunx cap sync 빌드 후. 확인 ios/App/App/public 및 android/app/src/main/assets/public 포함 index.html.
API 호출이 앱에서만 실패합니다. CORS: 허용 capacitor://localhost 및 https://localhost. 또한 호출하지 않는지 확인하세요 http:// iOS가 기본적으로 차단하는 URL
새로고침 또는 딥링크 후 404 오류 발생 다음으로 폴백하는 라우터를 사용하세요 index.html, 또는 구형 설정에는 해시 라우팅
Xcode 서명 오류 오류 목록은 iOS 인증서 및 provisioning profile 설명.
업그레이드 후 Gradle 빌드 실패 Capacitor 8은 Android Studio Otter(2025.2.1) 이상과 JDK 21이 필요하며, 이는 Capacitor 8 업그레이드 가이드에 나열되어 있습니다. 기타 Gradle 오류는 Capacitor에서 Android 빌드 오류 해결 방법.
대상 SDK에 대한 Google Play 업로드가 거부되었습니다. 설정 targetSdkVersion = 36 에서 android/variables.gradle.