CI CD — GitHub Actions + Fastlane으로 자동 배포
CI/CD — GitHub Actions + Fastlane으로 자동 배포
매번 수동으로 빌드하고 스토어에 올리는 것은 비효율적입니다. CI/CD를 구축하면 코드를 푸시하기만 해도 자동으로 테스트, 빌드, 배포가 진행됩니다.
CI/CD 파이프라인 흐름
Push/PR → 린트 & 테스트 → 빌드 → 배포
├─ Google Play (Android)
├─ App Store (iOS)
└─ Firebase App Distribution (테스트)
GitHub Actions — Flutter CI
# .github/workflows/ci.yml
name: Flutter CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
channel: 'stable'
cache: true
- name: 의존성 설치
run: flutter pub get
- name: 코드 분석
run: flutter analyze
- name: 포맷 확인
run: dart format --set-exit-if-changed .
- name: 테스트 실행
run: flutter test --coverage
- name: 커버리지 업로드
uses: codecov/codecov-action@v4
with:
file: coverage/lcov.info
build-android:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
cache: true
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: 의존성 설치
run: flutter pub get
- name: APK 빌드
run: flutter build apk --release
- name: AAB 빌드
run: flutter build appbundle --release
- name: 아티팩트 업로드
uses: actions/upload-artifact@v4
with:
name: android-release
path: |
build/app/outputs/flutter-apk/app-release.apk
build/app/outputs/bundle/release/app-release.aab
build-ios:
needs: test
runs-on: macos-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
cache: true
- name: 의존성 설치
run: flutter pub get
- name: iOS 빌드
run: flutter build ios --release --no-codesign
Fastlane — 스토어 배포 자동화
Android Fastlane 설정
cd android
fastlane init
# android/fastlane/Fastfile
default_platform(:android)
platform :android do
desc "Google Play 내부 테스트 트랙에 배포"
lane :deploy_internal do
upload_to_play_store(
track: 'internal',
aab: '../build/app/outputs/bundle/release/app-release.aab',
json_key: 'fastlane/play-store-key.json',
)
end
desc "Google Play 프로덕션 배포"
lane :deploy_production do
upload_to_play_store(
track: 'production',
aab: '../build/app/outputs/bundle/release/app-release.aab',
json_key: 'fastlane/play-store-key.json',
)
end
end
iOS Fastlane 설정
# ios/fastlane/Fastfile
default_platform(:ios)
platform :ios do
desc "TestFlight에 배포"
lane :deploy_testflight do
build_app(
workspace: "Runner.xcworkspace",
scheme: "Runner",
export_method: "app-store",
)
upload_to_testflight(
skip_waiting_for_build_processing: true,
)
end
desc "App Store에 배포"
lane :deploy_appstore do
build_app(
workspace: "Runner.xcworkspace",
scheme: "Runner",
)
upload_to_app_store(
submit_for_review: true,
automatic_release: true,
)
end
end
GitHub Actions + Fastlane 통합
# .github/workflows/deploy.yml
name: Deploy to Stores
on:
push:
tags:
- 'v*' # v1.0.0 같은 태그 푸시 시 실행
jobs:
deploy-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
cache: true
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: 키스토어 디코딩
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/app/keystore.jks
- name: key.properties 생성
run: |
echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > android/key.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
- name: 빌드
run: |
flutter pub get
flutter build appbundle --release
- name: Google Play 배포
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
- run: |
cd android
bundle install
bundle exec fastlane deploy_internal
env:
PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_STORE_JSON_KEY }}
Firebase App Distribution (테스트 배포)
# 개발 브랜치 푸시 시 테스터에게 배포
- name: Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_CREDENTIALS }}
groups: testers
file: build/app/outputs/flutter-apk/app-release.apk
버전 자동 증가
# pubspec.yaml
version: 1.0.0+1 # 버전이름+빌드번호
# GitHub Actions에서 빌드번호 자동 증가
- name: 빌드
run: flutter build apk --build-number=${{ github.run_number }}
시크릿 관리
GitHub Settings → Secrets and variables → Actions에 등록:
| 시크릿 | 용도 |
|---|---|
KEYSTORE_BASE64 | Android 서명 키 (base64) |
KEYSTORE_PASSWORD | 키스토어 비밀번호 |
KEY_PASSWORD | 키 비밀번호 |
KEY_ALIAS | 키 별칭 |
PLAY_STORE_JSON_KEY | Google Play API 키 |
FIREBASE_APP_ID | Firebase 앱 ID |
정리
- GitHub Actions로 푸시/PR 시 자동으로 린트, 테스트, 빌드를 실행합니다
- Fastlane으로 Google Play, App Store 배포를 자동화합니다
- 서명 키와 API 키는 GitHub Secrets에 안전하게 저장하세요
- 태그 기반 배포(
v*)로 릴리스 워크플로를 관리할 수 있습니다 - Firebase App Distribution으로 테스터에게 빠르게 배포할 수 있습니다
댓글 로딩 중...