RSS

Flutter 앱 배포, `flutter build` 한 줄이면 끝인 줄 알았습니다

모바일 앱글: , Duolabs11분 읽기blogci-cdfluttermobile-releasemodel-openai-gpt-5technical-note

Flutter 앱의 빌드 명령은 간단합니다. Android는 flutter build appbundle, iOS는 flutter build ipa로 결과물을 만들 수 있습니다. 그러나 팀이 반복해서 사용할 수 있는 배포 체계를 만들려면 그 뒤에 있는 서명, 권한, 스토어 API, 심사와 출시 절차까지 함께 설계해야 합니다.

이 글에서는 완전히 새로운 Flutter 프로젝트를 시작해 iOS와 Android를 CI/CD로 배포할 때 필요한 준비를 한 번에 정리합니다.

빌드, 업로드, 심사, 출시는 서로 다른 작업입니다

모바일 배포는 네 단계로 나뉩니다.

  1. 소스에서 IPA 또는 AAB를 빌드합니다.
  2. 결과물을 App Store Connect 또는 Google Play Console에 업로드합니다.
  3. 스토어 정보와 심사 답변을 검토한 뒤 심사를 요청합니다.
  4. 승인된 버전을 즉시, 예약 또는 단계적으로 공개합니다.

Fastlane이나 CI 서비스를 사용하면 이 흐름의 많은 부분을 자동화할 수 있습니다. 하지만 스토어의 법적 질문, 개인정보 선언, 가격, 공개 범위처럼 제품 책임이 필요한 결정은 승인 단계로 남겨 두어야 합니다.

Flutter가 대신 관리해 주지 않는 것들

Flutter는 크로스 플랫폼 UI와 앱 코드를 제공하지만 스토어 계정과 서명 체계를 대신 소유하지는 않습니다.

iOS

  • Apple Developer Program
  • App ID와 고유한 Bundle ID
  • App Store Connect 앱 레코드
  • 배포 인증서
  • App Store 배포용 프로비저닝 프로파일
  • App Store Connect API Key
  • iOS 빌드를 실행할 macOS와 Xcode 환경

CI에서는 인증서와 개인 키를 .p12로 안전하게 보관하고, 프로비저닝 프로파일과 함께 임시 keychain에 설치하는 방식이 흔합니다. App Store Connect 업로드 자동화에는 Issuer ID, Key ID, .p8 키가 별도로 필요합니다.

Android

  • Google Play Console 개발자 계정
  • 고유한 Application ID
  • Play Console 앱 레코드
  • Play App Signing
  • 업로드 keystore와 alias·비밀번호
  • Google Play Developer API 서비스 계정 JSON

Play App Signing을 사용하면 Google이 사용자에게 전달되는 앱 서명 키를 보호하고, 개발팀은 업로드 키로 새 AAB를 인증합니다. 업로드 키와 서비스 계정 키는 목적이 다르며 둘 다 저장소에 커밋하면 안 됩니다.

프로젝트를 만들 때 먼저 고정할 것

flutter create --org com.example example_app
cd example_app
flutter doctor -v
flutter pub get
flutter analyze
flutter test

팀과 CI가 같은 결과를 내도록 Flutter SDK 버전을 고정해야 합니다. 운영, 검증, 개발 환경이 서로 다른 서버나 Firebase 프로젝트를 사용한다면 flavor도 초기에 설계하는 편이 좋습니다.

예를 들면 다음처럼 역할을 구분할 수 있습니다.

  • dev: 개발 기능과 테스트 데이터
  • staging: 출시 후보 검증
  • production: 스토어 제출

각 flavor의 Bundle ID와 Application ID를 분리할지, 하나의 스토어 앱에서 설정만 바꿀지는 제품 운영 방식에 따라 결정합니다. 이 선택은 푸시 알림, 딥링크, Firebase 설정에도 영향을 줍니다.

Flutter의 버전은 일반적으로 pubspec.yaml에서 관리합니다.

version: 1.2.0+42

앞부분은 사용자에게 보이는 버전이고 +42는 빌드 번호입니다. 이미 업로드한 iOS 빌드 번호나 Android versionCode는 재사용할 수 없으므로 CI가 단조 증가하도록 만드는 것이 안전합니다.

로컬에서 확인할 빌드 명령

Android

flutter build appbundle --release

생성된 AAB를 내부 테스트 트랙에 먼저 올려 실제 기기 설치, 업데이트, 로그인, 딥링크, 결제와 알림을 확인합니다.

iOS

flutter build ipa --release

iOS 빌드는 macOS와 Xcode가 필요합니다. 생성된 IPA를 App Store Connect에 업로드한 뒤 TestFlight에서 검증합니다. TestFlight 업로드는 App Store 심사 제출과 별개의 단계입니다.

CI Secret 체크리스트

프로젝트 구조에 따라 이름은 달라질 수 있지만 보통 다음 정보를 암호화해 관리합니다.

  • App Store Connect Issuer ID, Key ID, .p8
  • iOS 배포 인증서 .p12와 비밀번호
  • iOS 프로비저닝 프로파일
  • Android 업로드 keystore
  • keystore 비밀번호, key alias, key 비밀번호
  • Google Play 서비스 계정 JSON

프로젝트 식별자, flavor 이름, 배포 트랙처럼 민감하지 않은 값은 일반 변수로 분리합니다. Secret은 운영 환경에만 주입하고, 로그 마스킹과 권한 최소화, 정기 교체 절차를 적용해야 합니다.

Firebase의 google-services.json 또는 GoogleService-Info.plist는 Play Store나 App Store 업로드 권한을 주는 키가 아닙니다. 또한 APNs 인증 키와 App Store Connect API Key도 용도가 다릅니다. 이름이 비슷한 파일을 하나의 “애플 키” 또는 “구글 키”로 묶어 관리하면 교체와 장애 대응이 어려워집니다.

Fastlane과 CI의 역할

Flutter 공식 문서는 배포 자동화 선택지로 Fastlane과 여러 CI 서비스를 안내합니다. Fastlane을 사용하면 다음 작업을 코드로 정리할 수 있습니다.

  • iOS 서명 준비와 IPA 업로드
  • TestFlight 배포
  • Android AAB 업로드
  • Google Play 트랙 승격
  • 스토어 메타데이터와 스크린샷 관리

CI 파이프라인은 운영체제 제약에 맞게 분리합니다.

  • Linux 실행 환경: 분석, 테스트, Android 빌드와 업로드
  • macOS 실행 환경: iOS 빌드, 서명, TestFlight 업로드

검증 단계는 모든 변경에서 실행하고, 스토어 업로드는 버전 태그나 수동 실행으로 제한하는 것이 좋습니다. 프로덕션 공개 단계에는 승인 담당자를 지정합니다.

권장 배포 시나리오

변경 검증

flutter pub get
flutter analyze
flutter test

Android

  1. 서명 설정을 CI에 주입합니다.
  2. release AAB를 생성합니다.
  3. Google Play 내부 테스트 트랙에 업로드합니다.
  4. 실제 기기 테스트를 완료합니다.
  5. 승인 후 비공개·공개 테스트 또는 프로덕션으로 승격합니다.

iOS

  1. 인증서와 프로비저닝 프로파일을 임시 keychain에 설치합니다.
  2. release IPA를 생성합니다.
  3. App Store Connect에 업로드합니다.
  4. TestFlight에서 검증합니다.
  5. 스토어 정보와 심사 답변을 확인한 뒤 App Review에 제출합니다.

빌드 산출물과 dSYM 같은 심볼 파일은 릴리스 버전과 연결해 보관해야 합니다. 장애가 발생했을 때 배포한 커밋, 사용한 SDK, 서명 정보, 스토어 빌드를 추적할 수 있어야 합니다.

자주 발생하는 실패

  • CI와 개발자의 Flutter 또는 Xcode 버전이 다릅니다.
  • iOS 인증서와 프로비저닝 프로파일의 Bundle ID가 맞지 않습니다.
  • Android 업로드 키와 Play App Signing 키의 역할을 혼동합니다.
  • 이미 사용한 빌드 번호로 다시 업로드합니다.
  • Linux 실행 환경에서 iOS 빌드를 시도합니다.
  • 내부 테스트 없이 프로덕션 공개를 자동 실행합니다.
  • 디버그 심볼과 빌드 로그를 남기지 않아 출시 후 오류를 분석하기 어렵습니다.

DUOLABS의 권장 기준

저희가 새 Flutter 프로젝트를 시작한다면 다음 원칙을 기본값으로 둡니다.

  • Flutter SDK와 주요 빌드 도구 버전을 명시적으로 고정합니다.
  • 개발·검증·운영 flavor의 목적과 앱 식별자를 문서화합니다.
  • Android는 내부 테스트, iOS는 TestFlight를 통과한 동일 커밋만 심사에 제출합니다.
  • 서명 키와 스토어 API 키의 소유자, 만료·교체 절차를 기록합니다.
  • 프로덕션 심사 제출과 공개에는 승인 단계를 둡니다.
  • Firebase와 푸시 서버 연결은 다음 확장 단계로 예약하되, 플랫폼 설정 파일과 서버 자격 증명의 책임 범위를 먼저 나눕니다.

핵심은 flutter build를 자동 실행하는 데 있지 않습니다. 누가 어떤 권한으로 어떤 결과물을 만들고, 어디에서 검증한 뒤, 어떤 승인으로 공개했는지를 다시 확인할 수 있어야 CI/CD가 완성됩니다.

공식 문서