fastlane 을 도입하게 된 계기
지난번에 CI/CD 도입기에서 Github Actions 로 파이프라인을 작성했었다.
그런데...
어느 순간 actions 실패 알림이 뜨더니 한계에 도달했다는 메시지가 떴다.
알고 보니까 우리 회사의 githgub 계정은 무료 플랜이라 월 2,000 분만 사용 가능했다.

그래서 어쩔 수 없이 CI 파이프라인은 유지하고 CD 라인만 오픈소스인 fastlane 으로 전환하기로 했다.
조만간 jenkins 서버를 구축한 다음에는 완전히 전환하려 한다.
Service Account 생성하기
GCP 에서 service account 를 준비해야 한다.
나는 Firebase 에서 생성을 했다.
Firebase 에서 프로젝트 설정을 들어간 후

서비스 계정으로 가준다.

여기서 서비스 계정 목록을 확인할 수 있다.
오른쪽에 서비스 계정 권한 관리로 들어가면 바로 GCP 서비스 계정으로 이동된다.
제일 위에 서비스 계정 만들기를 클릭하고, 계정 이름을 입력한다.
나는 그냥 fastlane 으로 입력했다.

그리고 완료를 누르면 아래와 같이 생성된걸 확인 할 수가 있다.

클릭해서 들어간 후에 위쪽 탭에서 키를 선택한다.

그런 다음 키 추가를 눌러서 '새 키 만들기' 를 클릭한다.
키 유형은 JSON 으로 만들기를 한다.

이 json 키 파일은 배포 권한을 가진 파일이기 때문에 유출에 주의해야 한다.
Fastlane 설치하기
1. ruby version 확인
fastlane 은 ruby 2.5 이상을 지원한다.
ruby --version
2. fastlane 설치
brew install fastlane
android 에서 fastlane 설정하기
1. android 폴더로 이동
현재 작업 중인 프로젝트에서 android 폴더로 이동한다.
cd android
2. fastlane 초기화
fastlane init
초기화를 하면 제일 처음 패키지 명을 입력하라고 나온다.
패키지 명을 입력하면 된다. (나중에 수정 가능)

패키지 명을 입력하고 나면 json secret file 의 경로를 입력하라고 나온다.
이건 이 글에서 제일 처음에 발급했던 그 json 파일이다.
나는 android/ 하위에 해당 파일을 위치시켰다.

다음으로 등록한 스토어 정보(metadata)를 다운로드 할 것인지에 대한 질문이다.
이미 배포한 앱을 자동화 하는 것이라면 N
새롭게 앱을 등록해야 한다면 Y

그 다음은.. 쭉쭉 엔터를 누르면 되고, fastlane 설정이 완료가 되었다.
이제 android 폴더 하위에 fastlane 폴더가 생성된 것을 확인할 수 있다.

먼저 Appfile 은 아까 입력한 json key file path 와 package name 이 입력되어 있다.
그리고 Fastfile 은 배포 스크립트를 작성해서 자동화 하는 파일이다.
그러면 Gemfile 은 뭔가? fastlane 파일들을 ruby 에서 관리하기 위한 파일이다.
(Android) 배포 스크립트 작성하기
default_platform(:android)
platform :android do
desc "Runs all the tests"
lane :test do
gradle(task: "test")
end
desc "Submit a new Beta Build to Crashlytics Beta"
lane :beta do
gradle(task: "clean assembleRelease")
crashlytics
# sh "your_script.sh"
# You can also use other beta testing services here
end
desc "Deploy a new version to the Google Play"
lane :deploy do
gradle(task: "clean assembleRelease")
upload_to_play_store
end
end
기본적으로 처음에 위와 같이 작성되어 있을 것이다.
desc... 를 포함해서 lane... 부터 end 까지가 한 세트이다.
여기서 lane :test, lane :beta, lane deploy 라 되어 있는데,
아래 명령어로각각 실행이 가능하다.
fastlane test
fastlane beta
fastlane deploy
이제부터는 원하는 파이프라인을 작성하면 된다.
우선 나는 아래와 같이 작성할 것이다.
- deploy playstore
- deploy firebase
- slack
아, 참고로 각 액션들은 함수(def)로 정의한 후에 lane 에서 함수를 호출할 것이다.
deploy playstore
# 옵션 참조: https://docs.fastlane.tools/actions/upload_to_play_store/
# PlayStore 에 배포 (alpha)
def deployToPlayStore(track = "alpha")
gradle(task: "clean assembleProdRelease") # flavor 때문에 Prod 가 붙어있음
gradle(
task: "bundle",
build_type: "release",
print_command: true,
)
# 개시
# 옵션 참조: https://docs.fastlane.tools/actions/upload_to_play_store/
upload_to_play_store(
track: track, # production, beta, alpha, internal
json_key: "fastlane-deploy.json", # service account 에서 발급받은 json key
aab: "../build/app/outputs/bundle/prodRelease/app-prod-release.aab",
skip_upload_metadata: true, # 메타데이터 업로드를 건너뛰는 경우
skip_upload_images: true, # 이미지 업로드를 건너뛰는 경우
skip_upload_screenshots: true, # 스크린샷 업로드를 건너뛰는 경우
skip_upload_apk:true # APK 업로드를 건너뛰는 경우
)
end
부연설명을 하자면,
나는 각 서버별로 flavor 로 구분해뒀기 때문에 2번째 줄에 assembleProdRelease 이고, 그게 아니라면 보통 assembleRelease 가 될 것이다.
배포는 알파 테스트까지만 자동으로 배포될 수 있도록 설정해뒀다.
내부 테스트 이후에 알파 테스트든 프로덕션이든 버전 승급을 하기 위해서이다. (각자 기호에 따라..)
upload_to_play_store 의 옵션들에 대한 상세 설명은 여기에서 확인해주세요~!
그리고 추가로 signing 설정을 위해 dotenv 를 설치한 다음..
npm install dotenv
keystore 는 flutter 프로젝트 최상위에 .env 파일을 생성하여 위에서 선언한 KEYSTORE_PATH 등을 작성했다.
아 당연히 .env 파일은 .gitignore 에 추가하는건 잊지 말자!
deploy firebase
# firebase 에 배포 (Android)
def deployToFirebase(flavor)
gradle(task: "clean assemble#{flavor.capitalize}Release")
gradle(
task: "bundle",
build_type: "release",
print_command: true,
)
# firebase app id
app_id = case flavor
when "dev" then ENV["APP_ID_DEV"]
when "stg" then ENV["APP_ID_STAGE"]
when "prod" then ENV["APP_ID_PRODUCTION"]
end
# 옵션 참조: https://firebase.google.com/docs/app-distribution/android/distribute-fastlane?hl=ko#distribute
firebase_app_distribution(
app: app_id,
groups: "my-tester",
android_artifact_type: "APK",
android_artifact_path: "../build/app/outputs/flutter-apk/app-#{flavor.downcase}-release.apk"
)
end
추가 설명을 붙이자면,
나는 dev 와 prod 로 flavor 를 나눴다. (각각의 url 을 분리해서 빌드 테스트하기 위해)
떄문에 옵션으로 flavor 를 받고있다.
firebase 에서 앱 성성후 각 패키지마다 발급되는 app id 또한 env 에 추가해서 flavor 별로 적용했다.
send slack
# slack 전송
def send_slack_message(message)
slack(
message: message,
channel: "#채널명",
slack_url: "https://hooks.slack.com/services/..." # 여기에 자신의 채널의 웹훅 주소 입력
)
end
사용법은 아래와 같다.
default_platform(:android)
# .env 파일 읽어오기
require 'dotenv'
Dotenv.load('../../.env')
platform :android do
desc "firebase 배포"
lane :dev do |options|
flavor = options[:flavor] || "dev"
begin
deployToFirebase(flavor)
send_slack_message("✅ android 배포 성공! (Flavor: #{flavor}) 🚀")
rescue => error
send_slack_message("❌ android 배포 실패 (Flavor: #{flavor}): #{error}")
UI.error("배포 실패: #{error}")
end
end
desc "PlayStore 배포 (signing)"
lane :production do
begin
deployToPlayStore("alpha")
send_slack_message("✅ android 배포 성공! (Track: alpha) 🚀")
rescue => error
send_slack_message("❌ android 배포 실패 (Track: alpha): #{error}")
UI.error("배포 실패: #{error}")
end
end
end
shell script 로 한 번에 배포하기
저거 fastlane dev 나 fastlane production 을 치기 위해서 cd android... 이런 작업을 하는게 여간 귀찮은 일이 아니다.
또 ios 대로 또 이동해야 되고, 나 같은 경우는 flavor 옵션도 쳐줘야하기 때문에 더욱 까다로워졌다.
이럴 땐 바로 쉘 스크립트로 한번에 실행하기~~~!
배포 환경 입력받기
#!/bin/bash
# 기본값 설정
DEFAULT_ENVIRONMENT="dev"
DEFAULT_PLATFORM="android"
# 환경 옵션 확인
read -p "🌍 배포 환경을 입력하세요 (dev/stg/prod) [기본값: $DEFAULT_ENVIRONMENT]: " ENVIRONMENT
ENVIRONMENT=${ENVIRONMENT:-$DEFAULT_ENVIRONMENT} # 입력이 없으면 기본값 사용
case "$ENVIRONMENT" in
dev|stg|prod)
echo "🚀 [$ENVIRONMENT] 환경 세팅..."
;;
*)
echo "❌ 환경 옵션이 잘못되었습니다. (dev, stg, prod) 중 하나를 입력해주세요."
exit 1
;;
esac
첫번째로 배포 환경을 입력받았다.
flavor 로 구분을 안지었다면 이건 패스해도 된다.
난 서버별로 구분지었기 때문에 넣어줬다.
플랫폼 옵션 입력 받기
# 플랫폼 옵션 확인
read -p "📱 배포 플랫폼을 입력하세요 (android/ios/all) [기본값: $DEFAULT_PLATFORM]: " PLATFORM
PLATFORM=${PLATFORM:-$DEFAULT_PLATFORM} # 입력이 없으면 기본값 사용
함수 정의 후 실행하기
# 배포 함수 정의
deploy_android() {
echo "🚀 Android 배포 시작..."
cd android || exit 1 # cd 실패 시 즉시 종료
if [ "$ENVIRONMENT" = "prod" ]; then
fastlane production
else
fastlane dev flavor:$ENVIRONMENT
fi
cd .. || exit 1
}
deploy_ios() {
echo "🚀 iOS 배포 시작..."
cd ios || exit 1 # cd 실패 시 즉시 종료
if [ "$ENVIRONMENT" = "prod" ]; then
fastlane production
else
fastlane dev flavor:$ENVIRONMENT
fi
cd .. || exit 1
}
case "$PLATFORM" in
android)
deploy_android
;;
ios)
deploy_ios
;;
all)
deploy_android
deploy_ios
;;
*)
echo "❌ 플랫폼 옵션이 잘못되었습니다. (android, ios, all) 중 하나를 입력해주세요."
exit 1
;;
esac
입력받은 값들을 토대로 각 플랫폼에 정의된 Fastfile 내의 lane 들을 실행할 수 있도록 함수 지정해서 실행하도록 작성했다.
계속 연구 중..
fastlane 에 생각보다 많은 기능이 있는 것 같다.
스크린샷을 자동화해서 업로드하는 기능도 있다는데,
이건 조만간 공부해서 꼭 적용해보자!
추가로, IOS 도 조만간 작성할 예정이다..!
참조
'개발 > DevOps' 카테고리의 다른 글
| Flutter 에서 CICD 적용기 (with github actions) (0) | 2025.09.29 |
|---|---|
| CI/CD 도입 일지 (2) | 2024.12.16 |
| CI/CD 정의 (0) | 2022.12.21 |