[Growbit 2편] Next.js 웹앱을 위한 Capacitor iOS 배포 실전 가이드

Next.js로 만든 웹앱을 앱스토어에 올리려면 무엇부터 해야 할까요? 이번 글에서는 Growbit 습관 앱을 패키징하고, 본격적인 Capacitor iOS 배포와 앱스토어 제출을 준비하면서 정리한 실전 과정을 공유합니다.

웹 프론트엔드 개발자가 React Native나 Swift를 새로 배우지 않고도 모바일 앱 배포까지 이어가기 위해 반드시 확인해야 할 설정, 빌드 흐름, 앱스토어 심사 준비 포인트를 중심으로 정리했습니다.

Capacitor iOS 배포

1. 왜 2편은 Capacitor iOS 배포 과정인가

[지난 1편]에서는 Growbit을 만들며 Next.js와 Capacitor 조합을 선택한 이유를 정리했습니다. 핵심은 단순했습니다. 1인 개발자가 웹과 모바일을 따로 개발하면 제품 검증 속도가 크게 느려집니다. 그래서 먼저 Next.js로 핵심 경험을 만들고, Capacitor로 컨테이너를 생성해 단일 파이프라인을 구축하는 전략을 택했습니다.

하지만 여기서 많은 개발자가 한 번 더 막힙니다. 웹앱은 브라우저에 배포하면 끝이지만, 모바일은 Xcode 프로젝트, Bundle Identifier, 아이콘, 서명 인증서, 심사 대응까지 챙겨야 합니다. 특히 웹 프론트엔드 개발자에게는 코드보다 배포 환경 자체가 더 낯설게 느껴질 수 있습니다.

이번 글의 목표는 단순한 명령어 나열이 아닙니다. 성공적인 Capacitor iOS 배포를 위해 어떤 순서로 생각해야 하는지, 어떤 설정에서 실수가 많이 나는지, 그리고 앱스토어 심사 관점에서 하이브리드 앱을 어떻게 준비해야 하는지를 Growbit 사례를 기준으로 풀어보겠습니다.

2. Capacitor iOS 배포의 전체 흐름: 웹 빌드에서 앱스토어 제출까지

Next.js와 Capacitor를 함께 사용할 때 전체 흐름은 크게 다섯 단계로 나눌 수 있습니다.

  1. Next.js 앱을 정적 또는 웹뷰 친화적인 형태로 빌드합니다.
  2. Capacitor 프로젝트를 초기화하고 iOS 플랫폼을 추가합니다.
  3. 웹 빌드 결과물을 iOS 프로젝트로 동기화합니다.
  4. Xcode에서 앱 설정, 서명, 아이콘, 스플래시 화면을 정리합니다.
  5. Archive 빌드 후 App Store Connect로 업로드하고 심사를 준비합니다.

이 흐름에서 중요한 점은 Capacitor가 Next.js를 대신 빌드해 주는 도구가 아니라는 것입니다. 이미 만들어진 웹 결과물을 네이티브 앱 컨테이너에 담아주는 역할을 합니다. 따라서 웹 빌드가 먼저 안정적으로 성공해야 하고, 그다음 npx cap sync ios 명령을 통해 iOS 프로젝트에 반영하는 방식으로 접근해야 합니다.

Next.js 정적 빌드부터 Capacitor 동기화를 거쳐 Xcode 최종 패키징까지의 흐름도

3. 안정적인 설정을 위한 capacitor.config.ts의 핵심 값

Capacitor iOS 배포를 위해 초기화할 때 가장 먼저 마주하는 파일은 capacitor.config.ts입니다. 이 파일은 웹앱과 네이티브 앱 사이의 연결 정보를 정의하며, appId, appName, webDir 세 가지는 초기에 신중하게 정해야 합니다.

TypeScript

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

const config: CapacitorConfig = {
  appId: 'com.example.growbit',
  appName: 'Growbit',
  webDir: 'out',
  bundledWebRuntime: false,
};

export default config;
  • appId: iOS의 Bundle Identifier와 연결되는 값입니다. 일반적으로 도메인을 거꾸로 쓴 형태를 사용합니다. 푸시 알림 같은 네이티브 기능과도 직결되므로 신중하게 고정해야 합니다.
  • appName: 기기에 표시될 앱 이름입니다. 습관 앱의 브랜드 이름이 분명하다면 이 값을 일찍 고정하는 것이 이후 아이콘 작업에 도움이 됩니다.
  • webDir: Next.js 빌드 결과물이 위치하는 폴더입니다. 정적 export 기반이라면 보통 out을 사용합니다. 이 경로가 어긋나면 앱 실행 시 빈 화면이 뜨게 됩니다.

4. Next.js 빌드 결과물을 iOS 프로젝트에 동기화하기

실무에서 자주 헷갈리는 부분은 “웹 빌드”와 “네이티브 동기화”가 별개의 단계라는 점입니다. Next.js 코드를 수정했다고 해서 Xcode 프로젝트 안의 웹 리소스가 자동으로 바뀌지는 않습니다.

Bash

npm run build
npx cap sync ios
npx cap open ios

npm run buildout 폴더를 생성한 뒤, 반드시 npx cap sync ios를 실행하여 웹 빌드 결과물과 네이티브 플러그인 설정을 복사해야 합니다. 그다음 npx cap open ios를 실행하면 Xcode가 열리며 본격적인 배포 설정 단계로 넘어갑니다.

5. Xcode에서 반드시 확인해야 할 배포 설정

Xcode를 열면 설정 항목이 많아 막막할 수 있습니다. 완벽한 Capacitor iOS 배포를 위해 최소한 다음 세 가지 항목을 점검하세요.

5.1. Bundle Identifier

앱을 식별하는 고유한 값으로, Capacitor의 appId와 동일하게 맞춥니다. App Store Connect에 등록한 앱의 Bundle ID와 일치하지 않으면 업로드나 심사 준비 단계에서 에러가 발생합니다.

5.2. Signing & Capabilities

iOS 앱은 Apple Developer Program의 팀과 인증서를 통해 서명되어야 합니다. Xcode의 ‘Signing & Capabilities’ 탭에서 Team을 선택하고, Automatically manage signing을 켜두면 초기 배포 준비가 한결 수월해집니다.

5.3. Deployment Target

앱이 지원하는 최소 iOS 버전입니다. 최신 웹뷰 기능과 안정적인 터치 경험이 중요한 Growbit 같은 앱은 너무 오래된 버전을 지원하기보다, 현실적인 최신 사용자 기기 범위를 기준으로 타겟을 정하는 것이 유리합니다.

6. 앱 아이콘과 스플래시 화면은 심사 품질의 첫인상이다

앱스토어 심사에서 기능만큼 중요한 것이 완성도입니다. 웹뷰 앱이라고 해서 임시 이미지를 둔 채 제출하면 심사관과 사용자에게 신뢰를 주지 못합니다.

Growbit처럼 성취감을 주는 습관 앱의 경우, 디테일이 복잡한 일러스트보다는 한눈에 알아볼 수 있는 명확한 실루엣과 대비가 강한 아이콘이 적합합니다. 스플래시 화면(로딩 화면) 역시 브랜드 색상과 앱 이름이 짧은 순간 안정적으로 보이도록 AppIcon 에셋 카탈로그를 꼼꼼히 채워 넣어야 합니다.

7. 웹뷰 앱이 앱스토어 심사에서 조심해야 할 지점

Capacitor 앱이 웹뷰 기반이라고 해서 무조건 심사에 불리한 것은 아닙니다. 핵심은 ‘모바일 앱으로서 충분한 사용자 경험(UX)을 제공하는가’입니다.

  1. 외부 브라우저로 이동해야만 핵심 기능을 쓸 수 있는 구조는 아닌가?
  2. 홈 인디케이터, 노치, 터치 피드백 등 기기 특성이 고려되었는가?
  3. 오프라인 상태나 네트워크 오류 시 UI가 깨지지 않고 안내되는가?

또한, 사용자의 루틴 데이터를 다루는 습관 앱의 특성상 명확한 개인정보 처리방침 URL을 준비하여 App Store Connect 메타데이터에 등록해야 합니다.

8. 트러블슈팅: Capacitor iOS 배포 중 빈 화면이 뜰 때

Xcode 빌드도 성공했고 시뮬레이터도 켜졌는데, 하얀 빈 화면만 보일 때 점검해야 할 체크리스트입니다.

  • 경로 확인: capacitor.config.tswebDir가 Next.js 빌드 폴더(out)와 일치하는가?
  • 동기화 확인: npm run build 이후 npx cap sync ios를 빼먹지 않았는가?
  • 서버 전용 API 호출: windowlocalStorage 같은 클라이언트 API를 SSR(서버 렌더링) 단계에서 무턱대고 호출하여 Hydration 에러를 발생시키지 않았는가?

빈 화면은 대개 이 세 가지 원인 중 하나에서 비롯됩니다. Mac Safari의 ‘개발자용(Develop)’ 메뉴를 통해 시뮬레이터 웹뷰 콘솔을 열어보면 숨어있는 런타임 에러를 쉽게 찾을 수 있습니다.

9. 결론: 배포는 마지막 단계가 아니라 제품 경험의 일부다

Next.js 코드가 잘 돌아간다고 해서 곧바로 훌륭한 iOS 앱이 되는 것은 아닙니다. 성공적인 Capacitor iOS 배포를 이루기 위해서는 Xcode 세팅, 서명 인증, 스플래시 화면, 개인정보 처리방침 등 모바일 생태계의 문법을 기꺼이 학습하고 적용해야 합니다.

앱스토어에 올리는 순간부터 사용자는 웹사이트가 아니라 ‘앱’으로 평가합니다. 아이콘을 눌렀을 때의 첫 화면, 스와이프의 질감, 오류 메시지까지 모두 제품 경험의 일부입니다. 이 기준을 통과했을 때 비로소 1인 개발자의 웹 기술은 앱스토어까지 뻗어가는 강력한 실전 도구가 됩니다.

다음 글에서는 Growbit의 모바일 사용성을 극대화하기 위해 적용한 햅틱(진동) 피드백, 완료 애니메이션, 습관 유지 루프 설계에 대해 다루어 보겠습니다.

댓글 남기기