React Native 에서 Fastlane으로 배포 파이프라인 설계하기 (4. ios 의 Fastfile)

eeennsu·2026년 7월 22일

React Native

목록 보기
73/93

이제 ios/fastlane/Fastfile이 실제로 어떤 일을 자동화하는지, lane 단위로 뜯어본다. 앞 편에서 만든 서명·환경 토대(match, .env, 인증서) 위에 드디어 진짜 빌드·업로드 코드를 얹는 단계다.

아래에서 다루는 Fastfile은 3가지 환경(dev / beta / pro) 의 iOS 빌드를 TestFlight에 올리고, 빌드 직전·직후에 환경 분기(Info.plist·AppsFlyer·Firebase 설정 파일·Google OAuth URL scheme)를 자동으로 갈아끼운다. 사람이 Xcode를 열지 않아도, 명령 한 번에 대략 다음이 일어난다.

  1. App Store용 인증서·프로파일 동기화 (match)
  2. 환경별 설정 파일·번들 ID·표시 이름 교체 (셸 스크립트 + update_info_plist)
  3. 버전·빌드 번호 갱신 (increment_version_number / increment_build_number)
  4. Release archive → .ipa (build_app)
  5. TestFlight 업로드 (upload_to_testflight)
  6. (lane에 따라) dev 환경으로 복원 + git commit


1. 이 Fastfile이 굴러가려면 필요한 준비물

Fastfile 코드를 보기 전에, 이 코드가 바깥에 이미 있다고 가정하는 것들부터 정리한다. 이게 없으면 코드가 돌다가 멈춘다.

1) 환경 변수 (.env.<name>에서 주입)

앞 편에서 만든 .env.dev / .env.beta / .env.pro가 넘겨주는 값들이다. lane 안에서 ENV["..."]로 읽는다.

이름용도
APP_IDENTIFIER빌드할 환경의 Bundle ID (예: com.yourcompany.myapp.dev, com.yourcompany.myapp)
GOOGLE_CLIENT_URL_SCHEME현재 환경에서 쓸 Google 로그인(OAuth)용 URL scheme
DEV_GOOGLE_CLIENT_URL_SCHEMEbeta/pro 빌드가 끝난 뒤 dev로 되돌릴 때 쓰는 dev용 URL scheme

"URL scheme"이란 앱이 com.googleusercontent.apps.123...:// 같은 커스텀 주소로 자기를 열 수 있게 등록해둔 값이다. Google 로그인 후 브라우저가 다시 앱으로 돌아올 때 이 주소를 쓴다. 환경마다 OAuth 클라이언트가 다르면 이 값도 달라진다.


2) 외부 셸 스크립트

ios/fastlane/ 폴더에 같이 들어있는 bash 스크립트들이다. 환경 이름(dev/beta/pro)을 인자로 받아 네이티브 프로젝트 파일을 갈아끼운다. Fastfile은 sh "bash ./..."로 이 스크립트를 부른다.

스크립트역할
change_app_identifier.sh <env>네이티브 프로젝트의 Bundle ID를 환경별 값으로 교체
change_appsflyer_name.sh <env>AppsFlyer(마케팅 분석 SDK) 앱 이름·디버그 플래그 등 환경 분기
copy_config.sh <env>GoogleService-Info.plist(Firebase 설정 파일)를 환경별로 복사

여기서 중요한 발상 하나. 이 프로젝트는 환경을 Xcode의 scheme으로 나누지 않고, 셸 스크립트로 "그때그때 파일을 갈아끼우는" 방식을 쓴다. (그래서 뒤에 나오는 코드는 세 환경 모두 같은 MyApp scheme 하나만 쓴다.) 앞 편에서 소개한 "scheme별로 나누는 방법"과는 다른 접근인데, 둘 다 현업에서 흔히 쓴다. 이 편은 셸 스크립트 방식을 다룬다.


3) PlistBuddy

/usr/libexec/PlistBuddy는 macOS에 기본 내장된 plist 편집 CLI다. (plist는 Apple의 설정 파일 포맷. Info.plist가 대표적이다.) 여기서는 Google OAuth URL scheme을 Info.plist의 특정 위치에 직접 써넣는 데 쓴다.

PlistBuddy -c "Set :CFBundleURLTypes:1:CFBundleURLSchemes:0 com.googleusercontent.apps.XXX" Info.plist

:CFBundleURLTypes:1:CFBundleURLSchemes:0이라는 경로는 plist 구조를 파고드는 주소인데, "두 번째 URL Type → 그 안의 첫 번째 scheme" 을 가리킨다. (배열 인덱스가 0부터라 1이 두 번째다.) 즉 "이 자리에 Google OAuth scheme이 들어간다"고 프로젝트에서 약속해둔 위치다. 이 위치가 프로젝트마다 다를 수 있으니, 본인 Info.plistCFBundleURLTypes 배열을 열어 인덱스를 먼저 확인해야 한다.



2. 파일 상단 — 공통 상수와 헬퍼 함수

lane들 위에 공통으로 쓰는 값과 함수를 정의해둔다.

xcodeproj = "MyApp.xcodeproj"
workspace = "MyApp.xcworkspace"
plist_path = "MyApp/Info.plist"            # update_info_plist용 (Fastlane 기준 경로)
plist_buddy_path = "../MyApp/Info.plist"   # PlistBuddy용 (셸 작업 디렉토리 기준)
ios_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
podfile_path = File.join(ios_dir, "Podfile")  # 절대 경로

여기서 초보가 헷갈리기 쉬운 게 plist_pathplist_buddy_path../ 한 칸 차이라는 점이다. 이유는 이렇다. Fastlane의 update_info_plist 액션은 경로를 알아서 보정해주지만, sh로 직접 부르는 PlistBuddy작업 디렉토리(ios/fastlane/)를 기준으로 경로를 푼다. 그래서 실제 Info.plist가 있는 ios/MyApp/로 가려면 한 칸 위로 올라가는 ../가 붙는다. (같은 파일을 가리키는데 도구마다 기준점이 달라서 경로가 둘이 되는 것이다.)

def increment_patch_version(current_version)
  version_parts = current_version.split('.')
  major = version_parts[0].to_i
  minor = version_parts[1].to_i
  patch = version_parts[2].to_i + 1
  "#{major}.#{minor}.#{patch}"          # "1.2.11" → "1.2.12"
end

X.Y.Z 형식의 마케팅 버전을 받아 맨 끝자리(patch)를 +1 하는 헬퍼다. 뒤의 beta lane에서 "다음 버전 자동 제안"을 만들 때 쓴다.



3. Lane 한눈에 보기

lane빌드업로드버전 정하는 방식git commit용도
devOTestFlight대화형(현재 버전 유지 + 빌드 +1 제안)O개발용 배포
betaOTestFlight대화형(patch +1 제안, 2회 확인)O내부 QA용 정식 배포
proOTestFlight코드에 직접 박음X정식 출시용 배포
dev_modeXXX로컬을 dev 환경으로만 전환
beta_modeXXX로컬을 beta 환경으로만 전환
pro_modeXXX로컬을 pro 환경으로만 전환

*_mode lane들은 빌드/업로드 없이 환경 분기 파일만 갈아끼우는 용도다. 예를 들어 로컬 Xcode에서 직접 빌드·디버깅하면서 beta API/DB를 바라보고 싶을 때 bundle exec fastlane beta_mode --env beta를 쓴다.

원래 이 시리즈 초안에서는 dev lane을 "버전이 하드코딩된 가벼운 단발 빌드"로 설명했는데, 실제 코드의 dev lane은 beta처럼 대화형으로 버전을 입력받고 git commit까지 한다. 아래 흐름은 실제 코드 기준으로 정리한 것이다.



4. lane별 흐름

lane :dev — dev 빌드를 TestFlight에 업로드

lane :dev do
  app_identifier = ENV["APP_IDENTIFIER"]              # com.yourcompany.myapp.dev
  client_url_scheme = ENV["GOOGLE_CLIENT_URL_SCHEME"] # com.googleusercontent.apps.*
  match(type: "appstore")

  sh "bash ./change_app_identifier.sh dev"
  sh "bash ./change_appsflyer_name.sh dev"
  sh "bash ./copy_config.sh dev"

  sh %Q[/usr/libexec/PlistBuddy -c "Set :CFBundleURLTypes:1:CFBundleURLSchemes:0 #{client_url_scheme}" "#{plist_buddy_path}"]

  update_info_plist(
    xcodeproj: xcodeproj,
    plist_path: plist_path,
    app_identifier: app_identifier,
    display_name: "MyApp-dev"
  )

  # 버전 유지가 기본(빌드번호만 +1), No 선택 시 수동 입력
  current_version = get_version_number(xcodeproj: xcodeproj)
  current_build_number = get_build_number(xcodeproj: xcodeproj)
  suggested_version = current_version
  suggested_build_number = current_build_number.to_i + 1
  # ... UI.confirm 으로 자동/수동 분기 ...

  build_app(
    workspace: workspace,
    output_directory: "outputs/dev",
    scheme: "MyApp",
    xcargs: "-allowProvisioningUpdates",
    clean: true,
    disable_xcpretty: true,
    suppress_xcode_output: true,
    buildlog_path: "./outputs/dev"
  )
  upload_to_testflight(
    ipa: "outputs/dev/MyApp.ipa",
    skip_waiting_for_build_processing: true
  )

  git_commit(
    path: ".",
    message: "deploy(APP-00): ios dev - #{new_version}(#{new_build_number})",
    skip_git_hooks: false
  )
end

단계별로 풀면 이렇다.

  1. 인증서 동기화match(type: "appstore")로 App Store 인증서·프로파일을 키체인에 설치한다.
  2. 환경 전환 — 셸 스크립트 3개를 dev 인자로 호출해 Bundle ID·AppsFlyer 이름·Firebase 설정을 dev용으로 교체한다.
  3. OAuth scheme 주입PlistBuddyInfo.plist의 Google OAuth scheme을 dev 값으로 덮어쓴다.
  4. Info.plist 확정update_info_plist로 Bundle ID와 표시 이름(MyApp-dev)을 한 번 더 못 박는다.
  5. 버전 결정 (대화형) — 현재 버전을 읽어 "마케팅 버전은 그대로, 빌드 번호만 +1"을 제안한다. UI.confirm에서 Yes면 그 값으로, No면 UI.input으로 직접 입력받는다. (마케팅 버전은 유지하고 빌드 번호만 올리므로, TestFlight의 "같은 빌드 번호 재업로드 거부"에 걸리지 않는다.)
  6. archive·.ipa 생성build_app으로 Release archive와 .ipaoutputs/dev/에 만든다. xcargs: "-allowProvisioningUpdates"는 프로파일이 없을 때 Xcode가 자동으로 갱신하도록 허용하는 옵션이다.
  7. TestFlight 업로드upload_to_testflight. skip_waiting_for_build_processing: true라서 Apple의 처리 완료를 기다리지 않고 업로드 직후 종료한다.
  8. git commit — 바뀐 파일들을 deploy(APP-00): ios dev - {버전}({빌드}) 메시지로 커밋한다. (APP-00은 Jira/이슈 키 자리표시자다.)

dev lane은 beta/pro와 달리 완전 클린(rm -rf build·DerivedData 삭제)이나 cocoapods 재설치가 없고, 빌드 후 환경 복원도 없다. 가장 가볍게 굴리는 lane이다. (단, git commit은 한다.)


lane :beta — 패치 버전 자동 증가 + 2회 확인 + 복원 + commit

beta는 이 Fastfile에서 가장 손이 많이 가는 lane이다. 사용자 확인을 두 번 거치고, 완전 클린 빌드를 하고, 끝나면 환경을 dev로 되돌린 뒤 git commit까지 한다.

  1. 현재 버전 조회get_version_number / get_build_number로 현재 Info.plist 값을 읽는다.
  2. 자동 제안increment_patch_version으로 마케팅 버전 patch를 +1 하고, 빌드 번호는 새 버전 기준 1로 리셋한다.
  3. 사용자 확인 1차UI.confirm으로 "자동 버전으로 갈래? 아니면 직접 입력?"을 묻는다. No면 UI.input으로 버전·빌드 번호를 직접 받는다.
  4. 빈 값 가드 — 입력이 비어 있으면 UI.user_error!로 lane을 중단한다. (실수로 빈 값이 들어가 이상한 빌드가 올라가는 걸 막는다.)
  5. 사용자 확인 2차 — 한 번 더 UI.confirm. 확인을 두 번 둬서 잘못된 버전이 올라가는 사고를 예방한다.
  6. 완전 클린rm -rf build, ~/Library/Developer/Xcode/DerivedData/MyApp-* 삭제, xcodebuild clean. dev와 달리 매번 깨끗이 지운다.
  7. Pod 재설치cocoapods(clean_install: true)Pods/도 새로 받는다. 네이티브 의존성 변경이 누락 없이 반영되게 하려는 것이다.
  8. 인증서 동기화match(type: "appstore").
  9. 환경 전환 + OAuth + Info.plist — dev와 같은 패턴이되 인자가 beta, 표시 이름이 MyApp-beta.
  10. 버전 적용 — 위에서 정한 값으로 increment_version_number / increment_build_number.
  11. 빌드 + 업로드build_appupload_to_testflight. 산출물은 outputs/beta/.
  12. dev 환경으로 복원 — 셸 스크립트 3개를 다시 dev 인자로 호출하고, PlistBuddy로 OAuth scheme을 DEV_GOOGLE_CLIENT_URL_SCHEME으로 되돌린다. 빌드 직후 로컬이 beta 상태로 남으면 다음 개발 작업에 혼선이 생기므로 자동 복원하는 것이다.
  13. git commit — 바뀐 파일들(project.pbxproj, Info.plist, 설정 파일 등)을 deploy(APP-00): ios beta - {버전}({빌드}) 메시지로 커밋한다.

lane :pro — 정식 출시 빌드

beta와 거의 같지만 사용자 확인·자동 버전 증가·git commit이 전부 빠진 단순화 버전이다.

  1. 완전 클린 — beta와 동일 (build/DerivedData/Pods 모두).
  2. 인증서 동기화match(type: "appstore").
  3. 환경 전환pro 인자로 셸 스크립트 3개 + PlistBuddy.
  4. Info.plist 확정 — Bundle ID(com.yourcompany.myapp), 표시 이름(MyApp).
  5. 버전 하드코딩version_number: "1.2.11", build_number: 1. 매 배포 전에 이 두 값을 손으로 직접 수정해야 한다. beta 같은 자동 증가/입력 분기가 없다.
  6. 빌드 + 업로드build_appupload_to_testflight. 산출물은 outputs/pro/.
  7. dev 환경으로 복원 — beta와 동일한 복원 패턴. 단, beta에 있던 git_commit은 pro에는 없다. pro 빌드는 보통 release 태깅·별도 커밋으로 관리하는 정책이라 그렇다.
increment_version_number(
  version_number: "1.2.11",   # ← pro는 매 배포 전 이 값을 직접 수정
  xcodeproj: xcodeproj
)
increment_build_number(
  build_number: 1,            # ← 이 값도 직접 관리
  xcodeproj: xcodeproj
)

lane :dev_mode / :beta_mode / :pro_mode — 환경 전환 전용

빌드·업로드 없이 로컬 프로젝트를 해당 환경으로 전환만 한다.

  • 셸 스크립트 3개 + PlistBuddy + update_info_plist만 호출한다.
  • dev_mode에는 주석 처리된 increment_version_number·increment_build_number가 들어있다. 필요할 때 주석을 풀어 수동으로 버전을 박는 용도다.
  • 용도: 로컬 Xcode에서 직접 빌드/디버깅하면서 특정 환경(예: beta DB·beta API)을 바라보게 하고 싶을 때.


5. 핵심 액션 참조

액션한 줄 설명
match별도 git 저장소에 암호화 저장된 인증서·프로파일을 내려받아 키체인에 설치
cocoapodspod install 실행. clean_install: truePods/를 통째로 재설치
update_info_plistInfo.plist의 Bundle ID·표시 이름 등을 일괄 갱신
get_version_number / get_build_number현재 Info.plist에 박힌 마케팅 버전 / 빌드 번호 조회
increment_version_numberCFBundleShortVersionString(마케팅 버전) 설정
increment_build_numberCFBundleVersion(빌드 번호) 설정
build_app (= gym)Release archive 생성 + .ipa 추출. 내부적으로 xcodebuild 호출
upload_to_testflight (= pilot)App Store Connect API로 .ipa를 TestFlight에 업로드
git_commit변경된 파일들을 묶어 git commit (Fastlane 내장 액션)

build_app 옵션 풀이

build_app(
  workspace: workspace,                  # .xcworkspace 경로 (RN은 반드시 workspace)
  output_directory: "outputs/beta",      # .ipa·로그가 떨어질 폴더
  scheme: "MyApp",                       # 빌드할 Xcode scheme
  xcargs: "-allowProvisioningUpdates",   # 프로파일 누락 시 Xcode가 자동 갱신
  clean: true,                           # 빌드 전 clean
  disable_xcpretty: true,                # xcpretty 로그 포맷팅 끔
  suppress_xcode_output: true,           # Xcode raw 로그 콘솔 출력 억제
  buildlog_path: "./outputs/beta"        # 로그 파일 위치
)

RN 프로젝트는 CocoaPods를 쓰므로 .xcodeproj가 아니라 반드시 .xcworkspace를 넘겨야 한다. (1편에서 나온 그 이유다.)



6. 이 코드의 개선 방향 (선택)

앞서 말했듯 지금 Fastfile은 dev/beta/pro가 비슷한 코드를 복붙하고 있다. 규모가 커지면 아래처럼 다듬는 걸 권장한다. (초보 단계에선 몰라도 되고, "나중에 이렇게 줄일 수 있구나" 정도만 알아두면 된다.)

1) 공통 동작을 private_lane으로 묶기. 진입 lane(dev/beta/pro)은 얇게 두고, "환경전환 → 인증서 → 빌드 → 업로드" 공통 로직을 private_lane :build_and_upload 하나로 모으는 방식이다. 이렇게 하면 새 환경 추가가 lane 한 줄로 끝나고, 수정할 때 한 곳만 고치면 된다.

private_lane :build_and_upload do |options|
  env = options[:env]
  match(type: "appstore")
  sh "bash ./change_app_identifier.sh #{env}"
  # ... 공통 빌드/업로드 ...
end

lane :pro do
  build_and_upload(env: "pro")
  # pro만 추가로 dSYM을 Sentry에 업로드 같은 분기는 여기서
end

2) CI에서는 match(readonly: true). CI가 인증서를 새로 만들지 않고 기존 것만 내려받게 강제한다. 안 그러면 CI가 실수로 새 인증서를 발급해 개발자 계정당 인증서 한도(보통 배포용 3개)에 걸릴 수 있다. 지금 코드에는 없으니, CI에 붙일 때 추가하면 좋다.

3) 빌드 번호를 TestFlight 기준으로 자동 계산. 지금은 로컬 Info.plist 값을 기준으로 올리는데, latest_testflight_build_number + 1을 쓰면 "TestFlight에 이미 올라간 최대 빌드 번호 + 1"로 안전하게 잡을 수 있다. 이때 환경별 번들 ID가 다르므로 app_identifier를 함께 넘겨 환경별로 독립적인 번호가 유지되게 해야 한다. (더 정교한 버저닝은 다음 편에서 다룬다.)



7. package.json 스크립트 정리

터미널에서 매번 cd ios && bundle exec fastlane ...을 치기 번거로우니, package.json에 단축 스크립트를 등록해둔다.

{
  "scripts": {
    "deploy-ios-dev": "cd ios && bundle exec fastlane dev --env dev",
    "deploy-ios-beta": "cd ios && bundle exec fastlane beta --env beta",
    "deploy-ios-pro": "cd ios && bundle exec fastlane pro --env pro",

    "set-ios-dev": "cd ios && bundle exec fastlane dev_mode --env dev",
    "set-ios-beta": "cd ios && bundle exec fastlane beta_mode --env beta",
    "set-ios-pro": "cd ios && bundle exec fastlane pro_mode --env pro"
  }
}
  • deploy-ios-* → 실제 빌드·업로드까지 하는 dev/beta/pro lane
  • set-ios-* → 로컬 환경만 전환하는 *_mode lane

fastlane을 그냥 부르지 않고 bundle exec fastlane으로 부르는 이유는 1편에서 다룬 그대로다. Gemfile에 못 박은 버전으로 실행돼야 CI/로컬 간 버전 차이 사고를 막을 수 있으니, bundle exec 접두사는 빼지 않는다.



8. React Native 특화 주의사항

1) CocoaPods 동기화

build_app 전에 Pod이 최신이어야 한다. 위 beta/pro lane은 cocoapods(clean_install: true)로 매번 새로 받는데, 이게 시간이 오래 걸린다. 매 빌드마다 돌리기 싫다면 환경변수로 조건부 실행하는 방법도 있다.

cocoapods(
  clean_install: true,
  podfile: "./Podfile"
) if ENV["BUILD_PODS"] == "true"

2) JS 번들과 Hermes

React Native 0.70+ 부터 Hermes(자바스크립트 엔진)가 기본이다. build_app이 부르는 Xcode 빌드 단계에서 RN의 빌드 스크립트가 JS 번들 생성과 Hermes 바이트코드 변환을 자동으로 처리하므로, Fastfile에서 별도로 해줄 건 없다.

다만 Release 빌드 때 node가 PATH에 잡혀 있어야 한다. CI에서 가끔 node: command not found가 나면, Xcode 빌드 페이즈에서 PATH를 명시하거나 lane 안에서 ENV["PATH"]를 보강한다. (New Architecture를 쓰더라도 이 부분은 동일하다.)


3) 환경별 앱 아이콘/표시 이름 분리

dev/beta/pro를 한 폰에 동시에 깔면, 아이콘이 다 똑같아서 어느 게 어느 빌드인지 헷갈린다. 그래서 번들 ID뿐 아니라 아이콘·표시 이름도 나누는 게 좋다. (위 코드가 display_nameMyApp-dev/MyApp-beta/MyApp로 다르게 준 것도 이 때문이다.)

  • 표시 이름: update_info_plistdisplay_name으로 이미 분기 중.
  • 앱 아이콘: Build Configuration별로 다른 Assets.xcassets를 지정(ASSETCATALOG_COMPILER_APPICON_NAME 빌드 설정)하면 아이콘도 분리된다. (자세한 방법은 다음 편에서 다룬다.)


9. 자주 만나는 에러와 해결

1) "Code signing is required for product type 'Application'"

가장 흔한 에러다. 원인은 보통 둘 중 하나다.

  • match가 인증서를 깔았지만, Xcode 프로젝트의 signing이 여전히 "Automatic"으로 되어 있음
  • 번들 ID와 프로비저닝 프로파일의 ID가 안 맞음 (환경별 번들 ID를 나눴을 때 자주 발생)

해결: Xcode에서 Target → Signing & Capabilities → "Automatically manage signing" 체크를 끄고, Configuration별로 match AppStore com.yourcompany.myapp.dev 같은 환경별 프로파일을 직접 선택한다.


2) .env.dev 값이 안 먹는 것 같을 때

--env dev가 정말 로드됐는지 확인한다. 실행 로그에 Loading from '.env.dev'가 보여야 한다. 안 보이면 .env.devios/fastlane/에 있는지(다른 폴더 X), 파일명 오타가 없는지 확인한다.


3) "No code signing identity found"

Keychain에 인증서가 없거나, CI의 임시 keychain이 잠겨 있는 경우다. CI라면 before_all에서 setup_ci를 호출하도록 추가한다. (setup_ci는 CI용 임시 keychain을 만들어 잠금을 풀어주는 액션이다. 지금 이 Fastfile엔 없으니 CI에 붙일 때 넣어야 한다.)


4) "...Build Number ... already been used"

빌드 번호 충돌이다. 같은 빌드 번호로 두 번 올리려 해서 그렇다. dev/beta의 "빌드 +1" 로직이 제대로 도는지, 환경을 잘못 지정해 다른 번들 ID의 번호를 가져오지 않았는지 확인한다.


5) "Invalid Provisioning Profile"

대개 새 디바이스가 추가됐는데 프로파일이 갱신 안 된 경우다. 로컬에서 아래를 실행해 프로파일을 갱신한다.

bundle exec fastlane match development --env dev --force_for_new_devices

6) Apple Silicon 맥에서 ffi 관련 에러

일부 Ruby gem이 ARM 네이티브 빌드를 요구해서 난다. Gemfile이 있는 위치에서 아래를 실행한다.

bundle config set --local force_ruby_platform true
bundle install


11. 이번 편 정리

이번 편을 끝낸 시점의 상태는 다음과 같다.

  • ✅ dev/beta/pro 세 환경의 iOS 빌드를 TestFlight까지 자동 업로드
  • ✅ 빌드 전후로 번들 ID·설정 파일·OAuth scheme을 환경별로 자동 전환, beta/pro는 끝나면 dev로 복원
  • ✅ dev/beta는 대화형 버전 관리 + git commit, pro는 버전 하드코딩(수동 관리)
  • pnpm deploy-ios-*(배포) / pnpm set-ios-*(환경 전환) 단축 스크립트
  • ✅ 복붙 구조를 private_lane으로 줄이는 개선 방향까지 파악

다음 편에서는 Android 설정을 살펴본다.

profile
이력서 https://resume.eunsu.pro

0개의 댓글