이전글 🐥
[iOS] Fastlane + Github Action으로 CI/CD 구축하기(1) - Fastlane을 통한 TestFlight 업로드
이전글에 이어 이번엔 아래 내용들을 기록해보도록 하겠음
(1) Fastlane Match를 통해 인증서를 관리
(2) Github Action을 Fastlane과 연계해서 TestFlight 업로드 (Feat. SSH, Github Secrets)
Fastlane Match?
대부분의 블로그를 찾아보면 이 Match를 사용하는데 왜 사용할까에 대한 의문을 가졌음.
회사에서 팀으로 앱을 개발한다고 했을 때 인증서와 프로필을 관리한다면 인증서 만료 시점, 또는 새로운 기기에 설치한다고 했을 때 이 인증서를 갱신하고 다운로드 하는 과정에서 많은 리소스가 소모되게 됨.
그래서 match는 팀 전체에서 인증서와 프로필을 동기화해서 사용할 수 있게 해주어 관리에 드는 리소스를 줄여줌.
아래 문서에 상세하게 나와있으니 문서를 확인해보면 더 빠르게 이해할 수 있음.
Fastlane Match 사용법 (Private Github Repository 이용)
Match 설정 STEP
1. private으로 인증서를 관리할 레포를 생성
2. 터미널 > 프로젝트 폴더로 이동 - 아래 명령어로 MatchFile 생성
fastlane match init
fastlane 폴더 내부에 MatchFile 생성 된 것을 확인
3. Matchfile 작성
# git url
git_url("인증서 관리 Private Repository주소(SSH)")
storage_mode("git")
type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
verbose(true) # 로그를 확인하기 위해 작성, 없어도 상관없음
4. 기존 개발, 배포용 인증서 파기 및 match 생성
기존에 사용하던 인증서를 파기하고 Match로 변경해주는 작업을 할 것임
해당 작업에서 비밀번호(passphrase)를 요청하면 본인이 사용하는 비밀번호를 입력하고 기록해놓아야 함.
# 인증서 파기
fastlane match nuke development
fastlane match nuke distribution
# 인증서 생성
fastlane match development
fastlane match distribution
# 여기서부터는 다른 케이스
# 팀원에게 공유 (readonly로 하지않으면 재생성되기 때문에 항상 옵션을 붙여준다)
fastlane match appstore --readonly
fastlane match development --readonly
5. 인증서 관리용으로 생성한 Github Repository에서 파일이 제대로 생성되었는지 확인
6. 프로젝트 파일로 가서 Target > Signinig & Capabilites에서 provisioning Profile 변경 및 빌드 확인
Github Action + Fastlane 연동 및 TestFlight 업로드 (Feat. SSH, Github Secrets)
이제 Github Action으로 Fastlane을 연동할 것임.
Private 레포지토리에 인증서와 프로필이 있기 때문에 이 레포지토리에 접근하는 것이 필요함.
shimataro/ssh-key-action 을 통해 레포지토리에 대한 권한을 얻을 수 있는데 이 방법에 대해서 알아보도록 하겠음.
이 액션을 워크플로우에서 실행하기 이전에 Git SSH 설정이 선행되어야 함.
단계를 간단히 살펴보면
1) SSH 키 발급
2) 앱스토어 커넥트 API 키 발급
3) 프로젝트 레포 Github Secret 설정 (+ Slack Webhook URL 생성)
4) Gihub Action 설정 및 Fastfile 설정
SSH 설정 및 Github Secrets
아래 명령어를 수행하고
# Kown host값 알아내기
# 프로젝트 레포 상 Secret 설정
ssh-keyscan github.com | pbcopy -
# SSH Key 생성
# 프로젝트 레포 상 Secret 설정
ssh-keygen
# SSH 키 확인
ls -al ~/.ssh
# 개인키 복사
프로젝트 레포 상 Secret 설정
pbcopy < {KEY_FILE_NAME}
# 공개키 복사
# 인증서 저장된 레포지토리의 Deploy Key 설정
pbcopy < {KEY_FILE_NAME}.pub
인증서가 저장된 Private 레포지토리의 Settings/Deploy Keys에서 "Add deploy key"를 클릭 후 복사한 공개키를 넣어줌.
프로젝트 레포지토리의 Settings/Secrets and variables/Actions에 와서 "Repository Secrets"를 설정함.
아래 내용을 모두 입력해주어야 함.
SSH_KEY: 아래 명령어 실행 값
$ pbcopy < {KEY_FILE_NAME}
KNOWN_HOSTS: 아래 명령어 실행 값
$ ssh-keyscan github.com | pbcopy -
MATCH_PASSWORD: Match 설정시 사용했던 패스워드
FASTLANE_USER: Apple 개발자 계정
FASTLANE_PASSWORD: Apple 개발자 계정 패스워드
APP_STORE_CONNECT_API_KEY_ID: AppStoreConnect API Key ID
APP_STORE_CONNECT_API_ISSUER_ID: AppStoreConnect API Issuer ID
APP_STORE_CONNECT_API_KEY_CONTENT: AppStoreConnect API p8 file content
$ pbcopy < {P8_KEY_FILE_NAME}
KEYCHAIN_NAME: match에 사용될 keychain 이름. 임의 설정
KEYCHAIN_PASSWORD: match에 사용될 keychain 패스워드. 임의 설정
앱스토어 커넥트 관련 키 값은 여기 에서 키를 발급 다운받은 후
(1) issuer ID는 홈페이지 상에 나와있으니 기록해두고
(2) p8 파일은 다운로드 받은 후 pbcopy 명령어로 값을 기록해두면 됨
위의 설정들을 끝 마치면 다시 Github Action으로 돌아가 워크플레이스를 작성해주면 됨
참고로 pbcopy를 통해 나온 값에 어떤 것도 하지말고(지우던가 하는..) 붙여넣어줘야 오류가 안남
번외(Slack Webhook)
배포 진행상황을 slack으로 알리고 싶다면
slack webhook URL을 복사해둔 뒤 프로젝트 레포지토리의 secrets에 SLACK_URL 이란 이름으로 URL을 넣어둠
여기 에서 Slack Webhook 을 생성하는 방법을 확인해볼 수 있음.
Gihub Action 설정 및 Fastfile 설정
(1) Github Action 워크플로우 설정
Github에서 어떤 동작이 이루어질 때 실행될 것인지 설정할 수 있음(on 이후)
나는 tag(v*.*.*)나 release/v*.*.* 가 푸시될 때 동작하도록 설정함
가상머신에서 이루어질 job을 설정함
Fastlane 설치, SSH 설치, Fastlane 실행 등의 스탭으로 이루어짐.
여기서 환경변수(env)로 Secrets에 설정한 값들을 넣어주면 이 값을 Fastfile에서 ENV["환경변수명"]으로 사용할 수 있음.
Appstore.yml
# This workflow will build a Swift project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift
name: App Store
on:
push:
branches: [ "release/**" ]
tags: ["v*.*.*"]
jobs:
build:
name: CI/CD By Using Fastlane
runs-on: macos-latest
steps:
- name: Select Xcode version
run: sudo xcode-select -s /Applications/Xcode_16.2.app
# Git Repository Checkout
- name: Checkout Repository
uses: actions/checkout@v3
# Buiild 수행 Xcode 버전 설정
- name: Select Xcode Version
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
# APIKey 생성(필수 아님, 내 프로젝트는 API키가 .gitignore 처리 되어있어 설정함)
- name: Create APIKey.swift file
run: |
mkdir -p ./Rebit
echo 'import Foundation' > ./Rebit/APIKey.swift
echo 'enum APIURL { static let naver = "https://openapi.naver.com/v1/search/book.json" }' >> ./Rebit/APIKey.swift
echo 'enum APIKey {' >> ./Rebit/APIKey.swift
echo ' static let clientID = "${{ secrets.NAVER_CLIENT_ID }}"' >> ./Rebit/APIKey.swift
echo ' static let clientSecret = "${{ secrets.NAVER_CLIENT_SECRET }}"' >> ./Rebit/APIKey.swift
echo '}' >> ./Rebit/APIKey.swift
# Install fastlane
- name: Install fastlane
run: brew install fastlane
- name: Fastlane Version Check
run: fastlane --version
# Install SSH
- name: Install SSH key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.SSH_KEY }}
known_hosts: ${{ secrets.KNOWN_HOSTS }}
# Run Fastlane
- name: Run Fastlane
run: fastlane beta
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
KEYCHAIN_NAME: ${{ secrets.KEYCHAIN_NAME }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
Fastfile
배포중일 경우와 배포이후에 Slack 메시지를 보내도록 설정함
스탭은 아래와 같음
(1) 키체인 생성과 match 설정, App Store Key설정이 진행
(2) 빌드 넘버를 테스트 플라이트 상의 빌드번호 +1으로 자동으로 증가
(3) 앱 빌드
(4) 테스트 플라이트 업로드
default_platform(:ios)
platform :ios do
desc "Push a new beta build to TestFlight"
before_all do
ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] = "600"
end
after_all do |lane|
slack(message: "리빗 iOS 배포 완료 ⭐️")
end
error do |lane, exception|
slack(
message: exception.message,
success: false)
end
lane :test do
scan(
project: "Rebit.xcodeproj",
devices: ["iPhone 16 Pro"]
)
end
lane :beta do
# 키체인 생성
create_keychain(
name: ENV["KEYCHAIN_NAME"],
password: ENV["KEYCHAIN_PASSWORD"],
timeout: 1800,
default_keychain: true,
unlock: true,
lock_when_sleeps: false
)
# APP STORE CONNECT API KEY 및 Fastlane Match 설정
app_store_connect_api_key(
key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"],
issuer_id: ENV["APP_STORE_CONNECT_API_ISSUER_ID"],
key_content: ENV["APP_STORE_CONNECT_API_KEY_CONTENT"]
)
match(
git_url: "Match 저장 private Repository 주소 (SSH)",
storage_mode: "git",
type: "appstore",
readonly: true,
keychain_name: ENV["KEYCHAIN_NAME"],
keychain_password: ENV["KEYCHAIN_PASSWORD"]
)
# 빌드 넘버 자동증가
increment_build_number(
build_number: latest_testflight_build_number + 1,
xcodeproj: "프로젝트명.xcodeproj"
)
build_ios_app(
scheme: "Rebit",
destination: "platform=iOS Simulator,name=iPhone 16 Pro"
)
# 슬랙 연동
slack(message: "리빗 iOS 배포 진행중 ⭐️")
# 테스트 플라이트 업로드
upload_to_testflight
end
end
위와 같이 설정하고 워크플로우에 설정한 이벤트를 발생시키면(Push) 테스트 플라이트에 업로드 되고 슬랙으로 결과를 받아볼 수 있음.
참고자료
Fastlane Match설정 및 Github Action연동
https://jazz-the-it.tistory.com/54https://littlemoom.tistory.com/51
slack Webhook 연동
https://velog.io/@king/slack-incoming-webhook
https://devinn.dev/blog/detail/362
github 태그
https://velog.io/@jhyeom1545/Git-Github-tag%EB%8B%A4%EB%A3%A8%EA%B8%B0-realease
Code Signing
https://gyuios.tistory.com/272#google_vignette
'iOS > iOS 지식' 카테고리의 다른 글
[iOS] Fastlane CI/CD 구축 시 발생 오류 및 해결법 (0) | 2025.03.14 |
---|---|
[iOS] Fastlane + Github Action으로 CI/CD 구축하기(1) - Fastlane을 통한 TestFlight 업로드 (2) | 2025.03.13 |
Swift Concurrency(3) - Behind the scenes (0) | 2025.02.25 |
[iOS] Keychain으로 민감정보 저장하기 (2) | 2025.02.25 |
[iOS] StackView의 Distribution과 Alignment (0) | 2024.11.28 |