안녕하세요 접니다 ㅋ
https://ukseung2.tistory.com/entry/iOS-Fastlane-Github-Action을-활용한-자동배포-1
[iOS] Fastlane + Github Action을 활용한 자동배포 [1]
안녕하세요 욱승입니다 🙇🏻♂️이번 포스팅은 미루고 미뤄왔던 Fastlane + Github Action을 활용한 자동배포를 진행 해볼거에요이 두개의 tool은 무료로 사용 가능하며 강력한 기능을 제공하기 때
ukseung2.tistory.com
에 이어서 진행을 해볼궤여 ㅋ
Github Action Code
name: Fastlane CI
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
jobs:
fastlane:
name: Run Fastlane
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.1 # Fastlane가 지원하는 Ruby 버전을 지정합니다.
- name: Install Bundler
run: gem install bundler
- name: Install dependencies
run: bundle install
- name: Output Fastlane environment
run: bundle exec fastlane env
- name: Run upload_testflight
if: github.ref == 'refs/heads/develop'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane upload_testflight
- name: Run release_app_store on master
if: github.ref == 'refs/heads/master'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane release_app_store
저 env에 있는 secrets들은 이 블로그를 참조해주세효
Github) Github actions에서 Secrets로 환경변수 관리하기
github actions는 github에서 제공하는 기능으로, 특정 트리거가 발동되었을 때 미리 설정한 워크플로를 실행시키는 자동화 툴이다. github actions를 활용하면 main 브랜치에 코드가 푸시되었을 때 자동으
velog.io
.yml 코드설명
Workflow Trigger
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
Trigger 조건: push와 pull_request 이벤트가 특정 브랜치(main, develop, master)에서 발생할 때 워크플로우가 실행됩니다.
Job 설정
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
Job 이름: "Run Fastlane"으로 정의.
실행 환경: macos-latest를 사용하여 macOS 환경에서 실행됩니다. iOS 앱 빌드 및 배포를 위해 macOS가 필요합니다.
1. Checkout Repository
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
작업: GitHub 저장소의 코드를 현재 작업 디렉토리로 가져옵니다.
토큰 사용: 인증에 필요한 GitHub 토큰을 사용하여 안전하게 체크아웃합니다.
2. Setup Ruby
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
Job 이름: "Run Fastlane"으로 정의.
실행 환경: macos-latest를 사용하여 macOS 환경에서 실행됩니다. iOS 앱 빌드 및 배포를 위해 macOS가 필요합니다.
3. Install Bundler
- name: Install Bundler
run: gem install bundler
작업: Ruby 의존성 관리 도구인 Bundler를 설치합니다.
4. Install Dependencies
- name: Install dependencies
run: bundle install
작업: 프로젝트의 Gemfile에 정의된 의존성들을 설치합니다.
5. Output Fastlane Environment
- name: Output Fastlane environment
run: bundle exec fastlane env
작업: Fastlane 환경 정보를 출력하여 설정이 올바른지 확인합니다.
6. Run upload_testflight (develop 브랜치에서만 실행)
- name: Run upload_testflight
if: github.ref == 'refs/heads/develop'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane upload_testflight
조건부 실행:
- 이 단계는 develop 브랜치에서만 실행됩니다.
작업:
- Fastlane의 upload_testflight lane을 실행하여 앱을 TestFlight에 업로드합니다.
- 여러 환경 변수(secrets)를 사용하여 인증 및 설정을 처리합니다.
7. Run release_app_store (master 브랜치에서만 실행)
- name: Run release_app_store on master
if: github.ref == 'refs/heads/master'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane release_app_store
조건부 실행:
- 이 단계는 master 브랜치에서만 실행됩니다.
작업:
- Fastlane의 release_app_store lane을 실행하여 앱을 App Store에 배포합니다.
Fastfile Code
일단 Full Code 갈겨
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
fastlane_require 'active_support'
fastlane_require 'active_support/core_ext/time'
fastlane_require 'dotenv'
#✅ 상수
SLACK_URL = ENV['SLACK_URL']
KEYCHAIN_NAME = ENV['KEYCHAIN_NAME']
KEYCHAIN_PASSWORD = ENV['KEYCHAIN_PASSWORD']
APP_IDENTIFIER = ENV['APP_IDENTIFIER']
MATCH_GIT_BASIC_AUTHORIZATION = ENV['MATCH_GIT_BASIC_AUTHORIZATION']
APP_STORE_CONNECT_API_KEY_KEY_ID = ENV['APP_STORE_CONNECT_API_KEY_KEY_ID']
APP_STORE_CONNECT_API_KEY_ISSUER_ID = ENV['APP_STORE_CONNECT_API_KEY_ISSUER_ID']
APP_STORE_CONNECT_API_KEY_CONTENT = ENV['APP_STORE_CONNECT_API_KEY_CONTENT']
GIT_PERSONAL_TOKEN = ENV['GIT_PERSONAL_TOKEN']
TEAM_ID = ENV['TEAM_ID']
default_platform(:ios)
platform :ios do
lane :upload_testflight do
begin
# ✅ App Store Connect API 키 설정
# API 키를 사용하여 인증하여 App Store Connect에 접근
app_store_connect_api_key(
key_id: "#{APP_STORE_CONNECT_API_KEY_KEY_ID}",
issuer_id: "#{APP_STORE_CONNECT_API_KEY_ISSUER_ID}",
key_content: "#{APP_STORE_CONNECT_API_KEY_CONTENT}"
)
# ✅ CI 환경 설정
# CI/CD 환경에서 필요한 기본 설정 수행 (예: Xcode 설정, 환경 변수 설정 등)
setup_ci
# ✅ 코드 서명 인증서 및 프로비저닝 프로필 관리
# match를 사용하여 Apple Developer 계정에서 인증서 및 프로비저닝 프로필을 가져옴
match(
storage_mode: "git",
type: "appstore",
app_identifier: ["com.ukseung.Fastlane"],
readonly: false,
git_basic_authorization: Base64.strict_encode64("#{GIT_PERSONAL_TOKEN}"),
generate_apple_certs: false
)
# ✅ 빌드 번호 업데이트 (년월일시분초 기반)
# Fastlane의 increment_build_number를 사용하여 빌드 번호를 자동 증가시킴
increment_build_number(
xcodeproj: "Fastlane-Example.xcodeproj",
build_number: date_based_build_number
)
# ✅ 프로젝트의 팀 ID 업데이트
# Xcode 프로젝트의 팀 ID를 설정하여 코드 서명 오류 방지
update_project_team(
path: "../Fastlane-Example/Fastlane-Example.xcodeproj",
teamid: "#{TEAM_ID}"
)
# ✅ 앱 빌드 및 Export
# Xcode 프로젝트를 빌드하고 .ipa 파일을 생성하여 TestFlight에 업로드 준비
build_app(
workspace: "Fastlane-Example.xcworkspace",
scheme: "Fastlane-Example",
export_method: "app-store",
export_options: {
method: "app-store",
signingStyle: "manual",
provisioningProfiles: {
"com.ukseung.Fastlane" => "match AppStore com.ukseung.Fastlane"
}
}
)
# ✅ TestFlight 업로드
# 빌드한 .ipa 파일을 TestFlight에 업로드
upload_to_testflight(skip_waiting_for_build_processing: true)
# ✅ Slack 알림 전송 (성공)
# TestFlight 업로드 성공 시 Slack으로 알림 전송
send_slack_message("✅ TestFlight 배포 됐습니다 😎")
rescue => error
# ❌ TestFlight 업로드 실패 시 처리
# 실패 메시지를 Slack으로 전송하고, Fastlane에 오류를 전달하여 실행 중단
send_slack_message("❌ TestFlight 배포 실패했습니다 😭\nError: #{error}", false)
raise error # 실패를 Fastlane에 전달
end
end
# ✅ App Store 배포 Lane
lane :release_app_store do
begin
# ✅ App Store Connect API 키 설정
app_store_connect_api_key(
key_id: "#{APP_STORE_CONNECT_API_KEY_KEY_ID}",
issuer_id: "#{APP_STORE_CONNECT_API_KEY_ISSUER_ID}",
key_content: "#{APP_STORE_CONNECT_API_KEY_CONTENT}"
)
# ✅ CI 환경 설정
# CI/CD 환경에서 필요한 기본 설정 수행 (예: Xcode 설정, 환경 변수 설정 등)
setup_ci
# ✅ 코드 서명 인증서 및 프로비저닝 프로필 관리
# match를 사용하여 Apple Developer 계정에서 인증서 및 프로비저닝 프로필을 가져옴
match(
storage_mode: "git",
type: "appstore",
app_identifier: ["com.ukseung.Fastlane"],
readonly: false,
git_basic_authorization: Base64.strict_encode64("#{GIT_PERSONAL_TOKEN}"),
generate_apple_certs: false
)
# ✅ 빌드 번호 업데이트 (년월일시분초 기반)
# Fastlane의 increment_build_number를 사용하여 빌드 번호를 자동 증가시킴
increment_build_number(
xcodeproj: "Fastlane-Example.xcodeproj",
build_number: date_based_build_number
)
# ✅ 프로젝트의 팀 ID 업데이트
# Xcode 프로젝트의 팀 ID를 설정하여 코드 서명 오류 방지
update_project_team(
path: "../Fastlane-Example/Fastlane-Example.xcodeproj",
teamid: "#{TEAM_ID}"
)
# ✅ 앱 빌드 및 Export
# Xcode 프로젝트를 빌드하고 .ipa 파일을 생성하여 AppStore에 업로드 준비
build_app(
workspace: "Fastlane-Example.xcworkspace",
scheme: "Fastlane-Example",
export_method: "app-store",
export_options: {
method: "app-store",
signingStyle: "manual",
provisioningProfiles: {
"com.ukseung.Fastlane" => "match AppStore com.ukseung.Fastlane"
}
}
)
# ✅ AppStore 업로드 🎉
deliver(
submit_for_review: true,
force: true,
skip_screenshots: true,
automatic_release: true,
precheck_include_in_app_purchases: false,
copyright: "© #{Time.now.year} COMPANY-NAME, Inc.",
release_notes: {
"en-US" => "WHATS NEW"
},
app_review_information: {
demo_user: "demo@user.net",
demo_password: "DEMO-PASSWORD"
},
submission_information: {
export_compliance_encryption_updated: false,
export_compliance_uses_encryption: false,
add_id_info_uses_idfa: false
}
)
send_slack_message("✅ App Store 배포 완료 😎")
rescue => error
send_slack_message("❌ App Store 배포 실패 😭\nError: #{error}", false)
raise error
end
end
# ✅ Slack 메시지 전송 함수
def send_slack_message(message, success = true)
version = get_version_number(xcodeproj: "Fastlane-Example.xcodeproj") # Xcode 프로젝트의 버전 가져오기
full_message = "iOS #{version}(#{date_based_build_number})\n\n#{message}"
slack(
message: full_message,
success: success,
slack_url: "#{SLACK_URL}"
)
end
# ✅ 날짜 기반 빌드 번호 생성 함수
def date_based_build_number
Time.now.in_time_zone("Asia/Seoul").strftime("%Y.%m%d.%H%M")
end
end
주석을 열심히 달긴 했는데
이해가 안되는 부분은 댓글 주세요(항시 대기)
fastlane - App automation done right
The easiest way to build and release mobile apps. fastlane handles tedious tasks so you don’t have to. Developer hours saved 10,558,200
fastlane.tools
CI/CD 환경에서 Match는 선택이 아니고 필수입니다
Match가 뭐냐하면..
ref.
fastlane match를 통해 팀원들과 인증서 공유하기
안녕하세요. 그린입니다 🍏이번 포스팅에서는 Fastlane match를 사용하여 팀원들과 인증서를 공유하고 또 배포까지 한번 해보도록 하겠습니다 🙋🏻 match?우선, 팀원들과 협업하면서 Fastlane을 이
green1229.tistory.com
이보다 더 정리를 잘 할수 없을것 같아 그린님의 블로그로 대체합니다..
갓초록..
이렇게만 코드 적용하면 CI/CD 환경에서도 TestFlight 업로드 가능!

삽질하다가 72번째만에 자동배포가 되었다는 사실..
결론 및 느낀점
미루고 미뤄왔던 Fastlane 포스팅을 마쳤다,,
무료 tool인 Git과 Fastlane을 통해 자동배포를 진행해보았고
master 브랜치에 Push 하면 AppStore 배포, develop 브랜치에 Push하면 TestFlight 배포가 되는 쾌거를 이루었음..
그리고 모든 프로젝트에 적용할 예정이다.
TestFlight 배포 및 AppStore 업로드를 자주 한다고 돈이 드는건아니니..
인증서 부분에서 꽤나 애를 먹었으나.. 극복
그럼 20000

'iOS > Fastlane' 카테고리의 다른 글
[iOS] Fastlane + Github Action을 활용한 자동배포 [1] (2) | 2025.04.01 |
---|
안녕하세요 접니다 ㅋ
https://ukseung2.tistory.com/entry/iOS-Fastlane-Github-Action을-활용한-자동배포-1
[iOS] Fastlane + Github Action을 활용한 자동배포 [1]
안녕하세요 욱승입니다 🙇🏻♂️이번 포스팅은 미루고 미뤄왔던 Fastlane + Github Action을 활용한 자동배포를 진행 해볼거에요이 두개의 tool은 무료로 사용 가능하며 강력한 기능을 제공하기 때
ukseung2.tistory.com
에 이어서 진행을 해볼궤여 ㅋ
Github Action Code
name: Fastlane CI
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
jobs:
fastlane:
name: Run Fastlane
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.1 # Fastlane가 지원하는 Ruby 버전을 지정합니다.
- name: Install Bundler
run: gem install bundler
- name: Install dependencies
run: bundle install
- name: Output Fastlane environment
run: bundle exec fastlane env
- name: Run upload_testflight
if: github.ref == 'refs/heads/develop'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane upload_testflight
- name: Run release_app_store on master
if: github.ref == 'refs/heads/master'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane release_app_store
저 env에 있는 secrets들은 이 블로그를 참조해주세효
Github) Github actions에서 Secrets로 환경변수 관리하기
github actions는 github에서 제공하는 기능으로, 특정 트리거가 발동되었을 때 미리 설정한 워크플로를 실행시키는 자동화 툴이다. github actions를 활용하면 main 브랜치에 코드가 푸시되었을 때 자동으
velog.io
.yml 코드설명
Workflow Trigger
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
Trigger 조건: push와 pull_request 이벤트가 특정 브랜치(main, develop, master)에서 발생할 때 워크플로우가 실행됩니다.
Job 설정
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
Job 이름: "Run Fastlane"으로 정의.
실행 환경: macos-latest를 사용하여 macOS 환경에서 실행됩니다. iOS 앱 빌드 및 배포를 위해 macOS가 필요합니다.
1. Checkout Repository
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
작업: GitHub 저장소의 코드를 현재 작업 디렉토리로 가져옵니다.
토큰 사용: 인증에 필요한 GitHub 토큰을 사용하여 안전하게 체크아웃합니다.
2. Setup Ruby
on:
push:
branches:
- main
- develop
- master
pull_request:
branches:
- main
- develop
- master
Job 이름: "Run Fastlane"으로 정의.
실행 환경: macos-latest를 사용하여 macOS 환경에서 실행됩니다. iOS 앱 빌드 및 배포를 위해 macOS가 필요합니다.
3. Install Bundler
- name: Install Bundler
run: gem install bundler
작업: Ruby 의존성 관리 도구인 Bundler를 설치합니다.
4. Install Dependencies
- name: Install dependencies
run: bundle install
작업: 프로젝트의 Gemfile에 정의된 의존성들을 설치합니다.
5. Output Fastlane Environment
- name: Output Fastlane environment
run: bundle exec fastlane env
작업: Fastlane 환경 정보를 출력하여 설정이 올바른지 확인합니다.
6. Run upload_testflight (develop 브랜치에서만 실행)
- name: Run upload_testflight
if: github.ref == 'refs/heads/develop'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane upload_testflight
조건부 실행:
- 이 단계는 develop 브랜치에서만 실행됩니다.
작업:
- Fastlane의 upload_testflight lane을 실행하여 앱을 TestFlight에 업로드합니다.
- 여러 환경 변수(secrets)를 사용하여 인증 및 설정을 처리합니다.
7. Run release_app_store (master 브랜치에서만 실행)
- name: Run release_app_store on master
if: github.ref == 'refs/heads/master'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
GIT_PERSONAL_TOKEN: ${{ secrets.GIT_PERSONAL_TOKEN }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_PASSWORD: ${{ secrets.MATCH_GIT_PASSWORD }}
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
run: bundle exec fastlane release_app_store
조건부 실행:
- 이 단계는 master 브랜치에서만 실행됩니다.
작업:
- Fastlane의 release_app_store lane을 실행하여 앱을 App Store에 배포합니다.
Fastfile Code
일단 Full Code 갈겨
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
fastlane_require 'active_support'
fastlane_require 'active_support/core_ext/time'
fastlane_require 'dotenv'
#✅ 상수
SLACK_URL = ENV['SLACK_URL']
KEYCHAIN_NAME = ENV['KEYCHAIN_NAME']
KEYCHAIN_PASSWORD = ENV['KEYCHAIN_PASSWORD']
APP_IDENTIFIER = ENV['APP_IDENTIFIER']
MATCH_GIT_BASIC_AUTHORIZATION = ENV['MATCH_GIT_BASIC_AUTHORIZATION']
APP_STORE_CONNECT_API_KEY_KEY_ID = ENV['APP_STORE_CONNECT_API_KEY_KEY_ID']
APP_STORE_CONNECT_API_KEY_ISSUER_ID = ENV['APP_STORE_CONNECT_API_KEY_ISSUER_ID']
APP_STORE_CONNECT_API_KEY_CONTENT = ENV['APP_STORE_CONNECT_API_KEY_CONTENT']
GIT_PERSONAL_TOKEN = ENV['GIT_PERSONAL_TOKEN']
TEAM_ID = ENV['TEAM_ID']
default_platform(:ios)
platform :ios do
lane :upload_testflight do
begin
# ✅ App Store Connect API 키 설정
# API 키를 사용하여 인증하여 App Store Connect에 접근
app_store_connect_api_key(
key_id: "#{APP_STORE_CONNECT_API_KEY_KEY_ID}",
issuer_id: "#{APP_STORE_CONNECT_API_KEY_ISSUER_ID}",
key_content: "#{APP_STORE_CONNECT_API_KEY_CONTENT}"
)
# ✅ CI 환경 설정
# CI/CD 환경에서 필요한 기본 설정 수행 (예: Xcode 설정, 환경 변수 설정 등)
setup_ci
# ✅ 코드 서명 인증서 및 프로비저닝 프로필 관리
# match를 사용하여 Apple Developer 계정에서 인증서 및 프로비저닝 프로필을 가져옴
match(
storage_mode: "git",
type: "appstore",
app_identifier: ["com.ukseung.Fastlane"],
readonly: false,
git_basic_authorization: Base64.strict_encode64("#{GIT_PERSONAL_TOKEN}"),
generate_apple_certs: false
)
# ✅ 빌드 번호 업데이트 (년월일시분초 기반)
# Fastlane의 increment_build_number를 사용하여 빌드 번호를 자동 증가시킴
increment_build_number(
xcodeproj: "Fastlane-Example.xcodeproj",
build_number: date_based_build_number
)
# ✅ 프로젝트의 팀 ID 업데이트
# Xcode 프로젝트의 팀 ID를 설정하여 코드 서명 오류 방지
update_project_team(
path: "../Fastlane-Example/Fastlane-Example.xcodeproj",
teamid: "#{TEAM_ID}"
)
# ✅ 앱 빌드 및 Export
# Xcode 프로젝트를 빌드하고 .ipa 파일을 생성하여 TestFlight에 업로드 준비
build_app(
workspace: "Fastlane-Example.xcworkspace",
scheme: "Fastlane-Example",
export_method: "app-store",
export_options: {
method: "app-store",
signingStyle: "manual",
provisioningProfiles: {
"com.ukseung.Fastlane" => "match AppStore com.ukseung.Fastlane"
}
}
)
# ✅ TestFlight 업로드
# 빌드한 .ipa 파일을 TestFlight에 업로드
upload_to_testflight(skip_waiting_for_build_processing: true)
# ✅ Slack 알림 전송 (성공)
# TestFlight 업로드 성공 시 Slack으로 알림 전송
send_slack_message("✅ TestFlight 배포 됐습니다 😎")
rescue => error
# ❌ TestFlight 업로드 실패 시 처리
# 실패 메시지를 Slack으로 전송하고, Fastlane에 오류를 전달하여 실행 중단
send_slack_message("❌ TestFlight 배포 실패했습니다 😭\nError: #{error}", false)
raise error # 실패를 Fastlane에 전달
end
end
# ✅ App Store 배포 Lane
lane :release_app_store do
begin
# ✅ App Store Connect API 키 설정
app_store_connect_api_key(
key_id: "#{APP_STORE_CONNECT_API_KEY_KEY_ID}",
issuer_id: "#{APP_STORE_CONNECT_API_KEY_ISSUER_ID}",
key_content: "#{APP_STORE_CONNECT_API_KEY_CONTENT}"
)
# ✅ CI 환경 설정
# CI/CD 환경에서 필요한 기본 설정 수행 (예: Xcode 설정, 환경 변수 설정 등)
setup_ci
# ✅ 코드 서명 인증서 및 프로비저닝 프로필 관리
# match를 사용하여 Apple Developer 계정에서 인증서 및 프로비저닝 프로필을 가져옴
match(
storage_mode: "git",
type: "appstore",
app_identifier: ["com.ukseung.Fastlane"],
readonly: false,
git_basic_authorization: Base64.strict_encode64("#{GIT_PERSONAL_TOKEN}"),
generate_apple_certs: false
)
# ✅ 빌드 번호 업데이트 (년월일시분초 기반)
# Fastlane의 increment_build_number를 사용하여 빌드 번호를 자동 증가시킴
increment_build_number(
xcodeproj: "Fastlane-Example.xcodeproj",
build_number: date_based_build_number
)
# ✅ 프로젝트의 팀 ID 업데이트
# Xcode 프로젝트의 팀 ID를 설정하여 코드 서명 오류 방지
update_project_team(
path: "../Fastlane-Example/Fastlane-Example.xcodeproj",
teamid: "#{TEAM_ID}"
)
# ✅ 앱 빌드 및 Export
# Xcode 프로젝트를 빌드하고 .ipa 파일을 생성하여 AppStore에 업로드 준비
build_app(
workspace: "Fastlane-Example.xcworkspace",
scheme: "Fastlane-Example",
export_method: "app-store",
export_options: {
method: "app-store",
signingStyle: "manual",
provisioningProfiles: {
"com.ukseung.Fastlane" => "match AppStore com.ukseung.Fastlane"
}
}
)
# ✅ AppStore 업로드 🎉
deliver(
submit_for_review: true,
force: true,
skip_screenshots: true,
automatic_release: true,
precheck_include_in_app_purchases: false,
copyright: "© #{Time.now.year} COMPANY-NAME, Inc.",
release_notes: {
"en-US" => "WHATS NEW"
},
app_review_information: {
demo_user: "demo@user.net",
demo_password: "DEMO-PASSWORD"
},
submission_information: {
export_compliance_encryption_updated: false,
export_compliance_uses_encryption: false,
add_id_info_uses_idfa: false
}
)
send_slack_message("✅ App Store 배포 완료 😎")
rescue => error
send_slack_message("❌ App Store 배포 실패 😭\nError: #{error}", false)
raise error
end
end
# ✅ Slack 메시지 전송 함수
def send_slack_message(message, success = true)
version = get_version_number(xcodeproj: "Fastlane-Example.xcodeproj") # Xcode 프로젝트의 버전 가져오기
full_message = "iOS #{version}(#{date_based_build_number})\n\n#{message}"
slack(
message: full_message,
success: success,
slack_url: "#{SLACK_URL}"
)
end
# ✅ 날짜 기반 빌드 번호 생성 함수
def date_based_build_number
Time.now.in_time_zone("Asia/Seoul").strftime("%Y.%m%d.%H%M")
end
end
주석을 열심히 달긴 했는데
이해가 안되는 부분은 댓글 주세요(항시 대기)
fastlane - App automation done right
The easiest way to build and release mobile apps. fastlane handles tedious tasks so you don’t have to. Developer hours saved 10,558,200
fastlane.tools
CI/CD 환경에서 Match는 선택이 아니고 필수입니다
Match가 뭐냐하면..
ref.
fastlane match를 통해 팀원들과 인증서 공유하기
안녕하세요. 그린입니다 🍏이번 포스팅에서는 Fastlane match를 사용하여 팀원들과 인증서를 공유하고 또 배포까지 한번 해보도록 하겠습니다 🙋🏻 match?우선, 팀원들과 협업하면서 Fastlane을 이
green1229.tistory.com
이보다 더 정리를 잘 할수 없을것 같아 그린님의 블로그로 대체합니다..
갓초록..
이렇게만 코드 적용하면 CI/CD 환경에서도 TestFlight 업로드 가능!

삽질하다가 72번째만에 자동배포가 되었다는 사실..
결론 및 느낀점
미루고 미뤄왔던 Fastlane 포스팅을 마쳤다,,
무료 tool인 Git과 Fastlane을 통해 자동배포를 진행해보았고
master 브랜치에 Push 하면 AppStore 배포, develop 브랜치에 Push하면 TestFlight 배포가 되는 쾌거를 이루었음..
그리고 모든 프로젝트에 적용할 예정이다.
TestFlight 배포 및 AppStore 업로드를 자주 한다고 돈이 드는건아니니..
인증서 부분에서 꽤나 애를 먹었으나.. 극복
그럼 20000

'iOS > Fastlane' 카테고리의 다른 글
[iOS] Fastlane + Github Action을 활용한 자동배포 [1] (2) | 2025.04.01 |
---|