Published on

Flutter iOS 빌드 Podfile.lock 충돌 해결 가이드

Authors

서론

Flutter로 iOS 빌드를 하다 보면 Android는 멀쩡한데 iOS에서만 갑자기 pod install 단계가 터지면서 빌드가 막히는 경우가 잦습니다. 특히 CI나 팀 작업에서 자주 보는 유형이 Podfile.lock 충돌입니다. 증상은 다양하지만 본질은 하나로 수렴합니다.

  • Podfile.lock이 가리키는 의존성 버전/체크섬과 실제 설치하려는 Pod 스펙이 달라짐
  • 플러그인(Flutter plugin) 버전 변화로 Podfile이 생성/변경되었는데 lock이 따라오지 못함
  • Ruby/CocoaPods 버전 차이, CDN 캐시, spec repo 상태 차이로 동일한 lock을 재현하지 못함

이 글에서는 “무작정 rm -rf Pods”를 넘어, 왜 충돌이 나는지를 로그로 판별하고, 가장 안전한 해결 순서팀/CI에서 재발 방지하는 운영 방법까지 정리합니다.

Podfile.lock 충돌이란 무엇인가

CocoaPods는 iOS 의존성을 관리할 때 두 가지를 핵심으로 봅니다.

  • Podfile: 어떤 Pod를 어떤 조건으로 설치할지(타겟, 플랫폼, 소스 등)
  • Podfile.lock: 실제로 설치된 Pod의 정확한 버전체크섬, 그리고 의존성 트리

Podfile.lock은 “이번 프로젝트는 이 버전 조합으로 빌드된다”라는 재현성의 기준입니다. Flutter 프로젝트에서는 ios/Podfile이 Flutter tooling과 플러그인에 의해 간접적으로 영향을 받기 때문에, 플러그인 변경이 곧 iOS Pod 의존성 변경으로 이어집니다.

자주 보이는 에러 메시지 패턴

아래 로그가 나오면 대개 lock과 실제 설치하려는 podspec이 어긋났다는 의미입니다.

[!] CocoaPods could not find compatible versions for pod "Firebase/CoreOnly":
  In snapshot (Podfile.lock):
    Firebase/CoreOnly (= 10.24.0)

  In Podfile:
    firebase_core (from `.symlinks/plugins/firebase_core/ios`) was resolved to 2.x, which depends on
      Firebase/CoreOnly (= 10.25.0)

또는 spec repo/CDN 문제로 checksum mismatch가 날 수도 있습니다.

[!] Error installing XYZ
[!] /usr/bin/git clone ...
... expected checksum ... got ...

요약하면:

  • 스냅샷(Podfile.lock) 기준 버전
  • 현재 플러그인/Podfile이 요구하는 버전

서로 다르면 충돌이 납니다.

원인 1) Flutter 플러그인 업데이트로 iOS Pod 의존성 변경

가장 흔한 케이스입니다.

  • pubspec.yaml에서 플러그인 버전을 올림
  • flutter pub get 이후 iOS 쪽에서 요구하는 Pod 버전이 변경됨
  • 그런데 Podfile.lock은 이전 버전을 고정하고 있어 충돌

해결 절차(권장)

  1. Flutter 의존성 정리
flutter clean
flutter pub get
  1. iOS Pod 재설치(업데이트 포함)
cd ios
pod repo update
pod install --repo-update
  1. 여전히 충돌하면 “필요한 Pod만” 업데이트
cd ios
pod update Firebase/CoreOnly
pod install

pod update는 lock을 변경하는 행위이므로, 무분별하게 전체 업데이트하기보다는 충돌 난 Pod만 지정하는 편이 안전합니다.

원인 2) 팀원이 커밋한 Podfile.lock과 내 로컬/CI 환경의 CocoaPods 버전 차이

CocoaPods 버전이 다르면 같은 Podfile.lock이라도 설치 과정에서 미묘하게 달라지거나, 특정 기능(특히 CDN/HTTP 관련)에서 실패할 수 있습니다.

체크 포인트

pod --version
ruby -v
which pod

해결 가이드

  • 팀에서 CocoaPods 버전을 고정하는 것이 최선입니다.
  • Ruby는 rbenv/asdf 등으로 버전 고정, CocoaPods는 Gem으로 고정합니다.

예시: Gemfile로 CocoaPods 고정

# ios/Gemfile
source "https://rubygems.org"

gem "cocoapods", "1.15.2"

설치/실행:

cd ios
bundle install
bundle exec pod install

CI에서도 bundle exec로 실행하면 재현성이 크게 올라갑니다.

원인 3) CocoaPods CDN/Spec repo 상태 불일치(캐시 문제)

특히 CI에서 간헐적으로 터지는 유형입니다.

  • 어떤 Podspec은 CDN에서 내려받는데
  • 캐시가 꼬이거나 네트워크 이슈로 spec이 부분적으로 갱신
  • lock과 맞지 않는 spec을 기준으로 해결하려다 실패

해결 절차

  1. spec repo 업데이트 강제
cd ios
pod install --repo-update
  1. CocoaPods 캐시 정리(필요 시)
pod cache clean --all
rm -rf ~/Library/Caches/CocoaPods
rm -rf ~/.cocoapods
  1. 다시 설치
cd ios
pod repo update
pod install

캐시 삭제는 시간이 오래 걸리므로, CI에서 항상 하진 말고 “간헐적 실패가 반복될 때” 최후의 카드로 쓰는 편이 좋습니다.

원인 4) Pods/Podfile.lock을 부분적으로만 지우는 잘못된 클린업 순서

많이들 Pods만 지우고 Podfile.lock은 남기거나, 반대로 lock만 지우는 식으로 처리합니다. 상황에 따라 맞을 수도 있지만, 원인에 따라 더 악화될 수 있습니다.

언제 Podfile.lock을 유지해야 하나

  • 팀이 lock을 커밋하고, 동일 버전 조합으로 재현이 목표일 때
  • 단순히 Pods 디렉터리나 DerivedData가 꼬였을 때

이 경우는 아래 정도로 충분합니다.

rm -rf ios/Pods ios/.symlinks ios/Flutter/Flutter.framework ios/Flutter/Flutter.podspec
cd ios
pod install

언제 Podfile.lock을 삭제해야 하나

  • 플러그인/Pod 요구 버전이 바뀌었는데 lock이 과거 버전을 고정하고 있을 때
  • lock 자체가 충돌의 원인일 때(로그에 “In snapshot (Podfile.lock)”이 명확히 찍힐 때)

이때는 lock을 지우고 재생성합니다.

rm -rf ios/Pods ios/Podfile.lock
cd ios
pod install --repo-update

다만 lock을 삭제하면 의존성 버전이 바뀔 수 있으므로, 변경된 Podfile.lock을 반드시 커밋하고 팀에 공유해야 합니다.

원인 5) Xcode/DerivedData와 빌드 캐시가 꼬여서 “충돌처럼 보이는” 경우

pod install은 성공했는데 Xcode 빌드에서 링크 에러가 나거나, 오래된 아티팩트를 참조하는 경우가 있습니다. 이때도 사람들이 Podfile.lock을 의심하지만 사실은 DerivedData 문제인 경우가 있습니다.

해결 절차

rm -rf ~/Library/Developer/Xcode/DerivedData
flutter clean
cd ios
pod install

그리고 Xcode에서 Product > Clean Build Folder도 함께 수행하면 좋습니다.

실전: 로그로 원인 분류하는 빠른 체크리스트

아래 질문에 예/아니오로 답하면 해결 방향이 빨라집니다.

  1. 에러에 In snapshot (Podfile.lock)이 찍히는가?
  • 예: lock이 원인일 확률 높음 → pod update (특정 Pod) 또는 lock 재생성
  1. 팀원은 되는데 내 PC/CI만 실패하는가?
  • 예: CocoaPods/Ruby 버전, CDN/spec repo, 캐시 문제 확률 높음 → bundle exec, --repo-update, 캐시 정리
  1. pod install은 되는데 Xcode 빌드에서만 깨지는가?
  • 예: DerivedData/빌드 캐시 문제 가능 → DerivedData 삭제

이런 식의 “원인-증상 매핑”은 분산 시스템 장애 대응과도 유사합니다. 재현 환경이 조금만 달라도 결과가 달라지는 점에서, 운영에서 403/timeout을 좁혀가는 방식과 닮았습니다. 비슷한 트러블슈팅 사고방식이 궁금하다면 Python httpx ReadTimeout·ConnectError 재시도 설계도 참고할 만합니다.

팀/CI에서 재발 방지: Podfile.lock 운영 원칙

1) Podfile.lock은 커밋할까?

대부분의 앱 프로젝트에서는 커밋하는 것이 권장됩니다.

  • 장점: iOS 의존성 재현성 확보, “내 컴퓨터만 됨” 감소
  • 단점: 플러그인 업데이트 시 lock 충돌이 더 자주 드러남(하지만 이는 문제를 조기에 드러내는 장점이기도 함)

Flutter 앱(특히 Firebase, 광고 SDK 등)처럼 iOS Pod 의존성이 무거운 경우 lock 커밋이 사실상 필수에 가깝습니다.

2) CI에서의 권장 명령

  • CocoaPods 버전 고정(Gemfile) + bundle exec
  • repo update는 필요 시에만(캐시/네트워크 비용 고려)

예시 스크립트:

flutter pub get
cd ios
bundle install
bundle exec pod install
cd ..
flutter build ios --release

간헐적으로 spec 문제를 겪는다면 bundle exec pod install --repo-update를 고려합니다.

3) 플러그인 업데이트 PR에는 Podfile.lock 변경을 반드시 포함

pubspec.lock만 바뀌고 Podfile.lock이 안 바뀐 PR은, iOS 빌드가 다른 사람 환경에서 깨질 가능성이 큽니다. PR 체크리스트에 아래를 넣어두면 좋습니다.

  • flutter pub get 후 iOS 빌드 성공
  • ios/Podfile.lock 변경 포함(필요 시)
  • CI에서 pod install 재현 확인

대규모 팀에서 이런 “잠금파일 규율”이 무너지면, 결국은 디버깅 시간이 늘어납니다. 이는 DB 데드락처럼 원인이 복합적인 장애에서 특히 비용이 커지는데, 트러블슈팅 접근법 관점에서는 PostgreSQL RDS deadlock_detected(40P01) 원인·해결처럼 원인을 계층적으로 분해하는 방식이 도움이 됩니다.

케이스별 처방전(요약)

A. 플러그인 업데이트 후 Pod 충돌

flutter clean
flutter pub get
cd ios
pod install --repo-update
# 필요 시
pod update <충돌난 Pod>

B. CI에서만 간헐 실패(spec/cdn/cache)

cd ios
pod install --repo-update
# 계속되면
pod cache clean --all
rm -rf ~/Library/Caches/CocoaPods ~/.cocoapods
pod repo update
pod install

C. 환경 차이(CocoaPods 버전)

cd ios
bundle install
bundle exec pod install

D. pod는 되는데 Xcode 빌드가 꼬임

rm -rf ~/Library/Developer/Xcode/DerivedData
flutter clean
cd ios
pod install

결론

Flutter iOS 빌드에서 Podfile.lock 충돌은 “CocoaPods가 이상함”이 아니라, 대부분 잠금파일이 보장하는 재현성과 현재 요구사항이 어긋난 결과입니다.

  • 로그에 In snapshot (Podfile.lock)이 보이면 lock이 핵심 단서
  • 무작정 전체 pod update 대신, 충돌 난 Pod만 업데이트하는 것이 안정적
  • 팀/CI에서는 Gemfile + bundle exec로 CocoaPods 버전을 고정하면 재발률이 크게 줄어듦

한 번 해결하고 끝내기보다, “왜 지금 lock이 깨졌는지”를 PR 단위로 추적 가능한 상태로 만들어두면 iOS 빌드 안정성이 확실히 올라갑니다.