fastlane으로 iOS 빌드와 TestFlight 업로드 자동화
Unity가 뽑아낸 Xcode 프로젝트를 대상으로, App Store Connect API 키로 인증해 TestFlight까지 올리는 lane을 만들었다. 설정 파일은 세 가지로 나눈다.
| 파일 | 역할 | 공유 범위 |
|---|---|---|
.env |
App Store Connect API 인증 키 | 개발자 계정(조직)별 |
Appfile |
번들 ID, Apple ID, 팀 ID | 앱별 |
Fastfile |
빌드·업로드 lane | 모든 프로젝트 공통 |
초기화
섹션 제목: “초기화”Xcode 프로젝트 루트에서 최초 1회 init한다.
fastlane init.env
섹션 제목: “.env”App Store Connect API로 인증하려면 세 가지 값이 필요하다. 앱이 서로 다른 개발자 계정에 속해 있으면 계정마다 값이 다르다.
ASC_KEY_ID=<API Key ID>ASC_ISSUER_ID=<Issuer ID>ASC_KEY_CONTENT=<.p8 키 내용>Appfile
섹션 제목: “Appfile”프로젝트마다 다르게 설정한다.
app_identifier("com.example.app") # The bundle identifier of your appapple_id("<apple-id>") # Your Apple Developer Portal username
itc_team_id("<itc-team-id>") # App Store Connect Team IDteam_id("<team-id>") # Developer Portal Team IDFastfile
섹션 제목: “Fastfile”모든 프로젝트가 같은 Fastfile을 쓴다. 흐름은 필수 옵션 검증, API 키 인증, 자동 서명 설정, TestFlight 최신 빌드 번호 조회 후 +1, 앱 빌드, Changelog 읽기, TestFlight 업로드 순이다.
default_platform(:ios)
platform :ios do desc "Build and upload to TestFlight" lane :beta do |options| # 필수 옵션 검증 UI.user_error!("Missing required option: :name") unless options[:name] UI.user_error!("Missing required option: :version") unless options[:version]
# App Store Connect API 인증 api_key = app_store_connect_api_key( key_id: ENV["ASC_KEY_ID"], issuer_id: ENV["ASC_ISSUER_ID"], key_content: ENV["ASC_KEY_CONTENT"], duration: 1200, in_house: false )
# 자동 코드 서명 설정 update_code_signing_settings( use_automatic_signing: true, path: "Unity-iPhone.xcodeproj" )
# 최신 빌드 넘버를 가져와서 증가 current_build_number = latest_testflight_build_number( version: options[:version], api_key: api_key )
increment_build_number( build_number: current_build_number + 1, xcodeproj: "Unity-iPhone.xcodeproj" )
# IPA 파일명 설정 ipa_name = "#{options[:name]}.ipa"
# 앱 빌드 build_app( workspace: "Unity-iPhone.xcworkspace", scheme: "Unity-iPhone", clean: true, export_options: { allowProvisioningUpdates: true, signingStyle: "automatic" }, output_directory: "./build", output_name: ipa_name, xcargs: "-allowProvisioningUpdates" )
# Changelog 파일 읽기 (없으면 기본값 사용) changelog_path = "./Changelog.txt" changelog = File.exist?(changelog_path) ? File.read(changelog_path) : "Empty Changelog."
# TestFlight 업로드 upload_to_testflight( api_key: api_key, changelog: changelog, ipa: "./build/#{ipa_name}" ) endendJenkins에서는 빌드 파라미터로 이름을 넘긴다.
fastlane beta name:"${IPA_NAME}"로컬에서는 이름을 직접 넣는다.
fastlane beta name:GameA앱마다 .env·Appfile 정보가 달라서, Jenkins 작업 공간 아래에 앱별 디렉토리를 따로 두고 관리한다.