앱공방

About

Works

Contact

Flutter 빌드 및 배포 자동화 구축기 (with Fastlane + Shell Script)

2025/10/22 updated
개발
flutter

3 min read

Flutter 빌드 및 배포 자동화 구축기 (with Fastlane + Shell Script)

Flutter 앱 개발을 하다 보면 iOS, Android, 개발용(dev)와 배포용(prod) 빌드를 반복적으로 배포하는 과정이 꽤나 번거롭습니다.

이번 글에서는 fitf앱에서 Fastlane과 Shell Script를 활용하여 Flutter 빌드 및 배포 자동화 파이프라인을 구축하는 방법을 공유합니다.

폴더 구조

1📦 Flutter Project 2┣ 📂ios 3┃ ┣ 📂fastlane 4┃ ┃ ┗ 📜Fastfile 5┃ ┣ 📜AuthKey_xxx.p8 6┣ 📂android 7┃ ┣ 📂fastlane 8┃ ┃ ┗ 📜Fastfile 9┃ ┣ 📜fastlane-account.json 10┣ 📂scripts 11┃ ┣ 📜deploy-dev.sh 12┃ ┗ 📜deploy-prod.sh 13┣ 📂libs 14...

설치

1brew install fastlane 2or 3sudo gem install fastlane

저는 gem을 사용하여 설치했습니다.

iOS

공식 문서에서 가장 추천하는 방법인 App Store Connect API를 사용하여 설정합니다. 이를 위해서는 App Store Connect API key를 생성하고 fastlane에 이 키를 등록하여 자동적으로 배포가 가능하도록 지정해주는 순서로 진행합니다.

App Store Connect API key 생성

App Store Connect API key는 https://appstoreconnect.apple.com/access/integrations/api 에서 생성합니다.

2

생성한 키는 iOS 프로젝트 루트에 AuthKey_xxx.p8 파일로 저장 후 .gitignore에 추가해서 github나 gitlab에 올리지 않도록 합니다. Issuer_id와 키 ID는 Fastfile에 입력해야하기 떄문에 따로 저장해둡니다.

fastfile 작성

1cd ios/ 2fastlane init
1

Manual setup을 선택후 계속 진행하면 fastlane 폴더가 추가되고 Fastfile이 생성됩니다. 아래는 fitf 프로젝트의 Fastfile 예시입니다.

1default_platform(:ios) 2 3platform :ios do 4 before_all do 5 ENV["SLACK_URL"] = "https://hooks.slack.com/services/{slack_webhook_url}" 6 end 7 8 after_all do |lane| 9 slack(message: "Successfully deployed iOS App") 10 end 11 12 error do |lane, exception| 13 slack( 14 message: exception.message, 15 success: false 16 ) 17 end 18 19 desc "Deploy TestFlight (DEV)" 20 lane :deployTestFlightDev do 21 build_app( 22 workspace: "Runner.xcworkspace", 23 scheme: "dev", 24 xcargs: "-allowProvisioningUpdates" 25 ) 26 27 upload_to_testflight( 28 api_key: app_store_connect_api_key( 29 key_id: "{key_id}", 30 issuer_id: "{issuer_id}", 31 key_filepath: "./AuthKey_{key_id}.p8", 32 ), 33 skip_waiting_for_build_processing: true 34 ) 35 end 36 37 desc "Deploy TestFlight (PROD)" 38 lane :deployTestFlightProd do 39 build_app( 40 workspace: "Runner.xcworkspace", 41 scheme: "prod", 42 xcargs: "-allowProvisioningUpdates" 43 ) 44 45 upload_to_testflight( 46 api_key: app_store_connect_api_key( 47 key_id: "{key_id}", 48 issuer_id: "{issuer_id}", 49 key_filepath: "./AuthKey_{key_id}.p8", 50 ), 51 skip_waiting_for_build_processing: true 52 ) 53 end 54end

iOS 스키마는 devprod로 구성되어 있고 각 lane의 실행 전 ENV["SLACK_URL"]을 설정하여 내장 slack 함수에서 사용할 수 있도록 합니다. 또한 각 lane의 실행 후 slack 함수를 통해 성공 또는 실패 메시지를 전송합니다. 이 부분은 생략하셔도 상관없습니다.

그리고 각 스키마에 대한 lane을 작성합니다. lane들은 해당 스키마에 대한 빌드 및 배포를 담당합니다. 여기서 필요한 key_idissuer_id, key_filepath는 아까 저장해둔 정보들을 사용하여 Fastfile에 작성하면 iOS fastlane 설정은 끝입니다. fastlane deployTestFlightProd 명령어로 자동 빌드 및 배포를 진행할 수 있습니다.

Android

Android 진행 과정은 google cloud console 에서 배포를 도와주는 Service Account를 생성, 배포를 위한 API를 활성화 해주고, play console에서 사용자 초대를 해주는 과정으로 이루어집니다.

cloud console

먼저 https://console.cloud.google.com/iam-admin/serviceaccounts/ 에 접속하여 새로운 Service Account를 생성합니다. 이후 해당 Service Account의 JSON 키를 생성 후 다운로드 받아 Android 프로젝트 루트에 fastlane-account.json 파일로 저장 후 .gitignore에 추가해서 github나 gitlab에 올리지 않도록 합니다.

3

다시 cloud console 에 접속하여 API 및 서비스 > + API 및 서비스 사용 설정 버튼으로 접속하여 google play android developer api를 검색하여 활성화 해줍니다.

5

play console

play console 에 접속후 사용자 및 권한 탭에서 신규 사용자 초대 버튼 클릭 후 아까 생성한 Service Account의 이메일을 입력하고 관리자 역할을 부여해준후 사용자 초대를 클릭합니다. 그러면 자동적으로 해당 Service Account에 업로드 가능한 권한이 부여됩니다.

4

fastfile 작성

그리고 Android 프로젝트 루트에서 fastlane init을 실행하여 Fastfile을 생성합니다. fastlane init 명령어를 실행하면 패키지명과 service account의 경로를 묻는데 설정해둔 패키지명과 아까 생성한 fastlane-account.json 파일을 경로를 입력해줍니다.

1cd android/ 2fastlane init 3com.example.app 4./fastlane-account.json

이렇게 하고 나면 AppFile과 FastFile이 생성되고 AppFile에 패키지명과 service account 키 경로가 지정됩니다. service account 연결 테스트를 진행하려면 아래 명령어를 입력해보시면 됩니다

1fastlane run validate_play_store_json_key
6

flutter에서 안드로이드 빌드시에는 저장위치가 프로젝트 루트에 생성되기 때문에 이에 맞는 fastfile을 작성해줍니다. 이 부분은 사용자 환경에 맞게 작성해주면 됩니다. flavor 적용된 경우와 안된 경우의 빌드 경로가 다르기 때문에 예시로 양 경우를 작성해보았습니다.

1default_platform(:android) 2 3platform :android do 4 # 안드로이드 빌드 및 배포 (flavor 적용 안된 경우) 5 desc "Deploy PlayStore" 6 lane :deployPlayStore do 7 yaml_file_path = "../../pubspec.yaml" 8 data = YAML.load_file(yaml_file_path) 9 version_and_no = data["version"].split("+") 10 version=version_and_no[0] 11 no=version_and_no[1] 12 13 Dir.chdir "../.." do 14 sh("flutter", "build", "appbundle", "--release", "--build-number", no, "--build-name", version) 15 end 16 17 upload_to_play_store( 18 track: "internal", 19 release_status: "draft", 20 skip_upload_metadata: true, 21 skip_upload_images: true, 22 skip_upload_screenshots: true, 23 aab_paths: "../build/app/outputs/bundle/release/app-release.aab", 24 ) 25 end 26 27 # 안드로이드 빌드 및 배포 (flavor 적용) 28 desc "Deploy PlayStore Prod" 29 lane :deployPlayStoreProd do 30 yaml_file_path = "../../pubspec.yaml" 31 data = YAML.load_file(yaml_file_path) 32 version_and_no = data["version"].split("+") 33 version=version_and_no[0] 34 no=version_and_no[1] 35 36 Dir.chdir "../.." do 37 sh("flutter", "build", "appbundle", "--release", "--build-number", no, "--build-name", version, "--flavor", "prod") 38 end 39 40 upload_to_play_store( 41 track: "production", 42 release_status: "draft", 43 skip_upload_metadata: true, 44 skip_upload_images: true, 45 skip_upload_screenshots: true, 46 aab_paths: "../build/app/outputs/bundle/prodRelease/app-prod-release.aab", 47 ) 48 end 49end

Shell Script 작성

매번 배포시 iOS, Android 따로 명령어를 치기 귀찮기 때문에 한번에 진행할 수 있는 Shell Script를 작성해보겠습니다. 프로젝트 루트에 scripts 폴더를 생성하고 deploy-prod.sh 파일을 생성하여 아래와 같이 작성해줍니다.

1# Deploy ios 2cd ios 3fastlane deployTestFlightProd 4 5# Deploy android 6cd ../android 7fastlane deployPlayStoreProd

이렇게 생성후 프로젝트 루트 터미널에서 ./scripts/deploy-prod.sh 커맨드를 입력하면 iOS, Android 한번에 배포가 진행됩니다.

© 2025. appstdo all rights reserved.