Published on

Flutter iOS 빌드 실패? CocoaPods 오류 7해결

Authors

서버나 안드로이드는 잘 도는데 iOS만 빌드가 깨지는 순간, 대부분 ios/ 아래의 CocoaPods 상태(락 파일, Podspec 해석, Xcode 설정, Ruby 환경, 캐시)가 어긋나 있습니다. 이 글은 Flutter iOS 빌드 실패를 유발하는 대표적인 CocoaPods 오류를 7가지로 분류하고, 각 케이스별로 가장 빠르게 정상화하는 실전 절차를 제공합니다.

문제는 대개 “한 번 꼬이면 계속 꼬이는 캐시/락/환경” 패턴을 보입니다. 이런 관점은 다른 빌드·배포 이슈에도 그대로 적용됩니다. 캐시가 꼬였을 때의 접근 방식은 Docker 빌드가 느릴 때 BuildKit 캐시 깨짐 복구 글과도 유사하고, 원인 추적 습관은 EKS CrashLoopBackOff 진단 - Pod 재시작 원인 추적 같은 글에서 다루는 방식과 결이 같습니다.


먼저 확인: iOS 빌드 파이프라인에서 CocoaPods가 하는 일

Flutter iOS 빌드는 대략 아래 흐름입니다.

  1. flutter build ios 또는 Xcode 빌드 실행
  2. ios/Podfile 기반으로 CocoaPods가 iOS 네이티브 의존성을 설치
  3. Pods.xcodeprojRunner.xcworkspace 생성/갱신
  4. Xcode가 워크스페이스를 빌드하면서 Swift/ObjC 및 플러그인 프레임워크를 링크

따라서 오류가 나면 “Flutter 코드 문제”라기보다 Pod 설치 단계, Podspec 해석, Xcode 프로젝트 설정, Ruby/CocoaPods 실행 환경, 캐시/락 파일 불일치가 원인인 경우가 많습니다.


공통 응급 처치: 대부분의 케이스에 먼저 시도할 5줄

아래는 많은 CocoaPods 계열 문제를 한 번에 정리하는 “초기화 루틴”입니다.

flutter clean
rm -rf ios/Pods ios/Podfile.lock
rm -rf ~/Library/Developer/Xcode/DerivedData
cd ios && pod repo update && pod install --verbose
cd .. && flutter build ios
  • Podfile.lock은 의존성 버전 고정이라, 플러그인/SDK 변경 후 충돌을 만들 수 있습니다.
  • DerivedData는 Xcode 빌드 산출물 캐시라, 모듈 캐시 충돌이나 오래된 설정이 남아 빌드를 깨뜨릴 수 있습니다.

이 루틴으로 해결되지 않으면, 아래 7가지 유형 중 어디에 속하는지 로그로 분류해 들어가면 됩니다.


해결 1) pod 명령 자체가 실패: Ruby/CocoaPods 환경 꼬임

증상 로그 예시

  • pod: command not found
  • You don't have write permissions for the /Library/Ruby/Gems/... directory
  • ffi 관련 에러, Ruby 버전 불일치

원인

macOS 기본 Ruby 또는 Homebrew Ruby, gem 권한, CocoaPods 버전이 섞이면 pod가 아예 실행되지 않거나 플러그인 설치가 실패합니다.

해결 절차(권장)

  1. CocoaPods 버전 확인
pod --version
ruby -v
  1. Homebrew Ruby를 쓰는 경우, gem 경로 충돌을 줄이기 위해 gem 설치 경로를 사용자 영역으로 두거나, 팀 표준을 정합니다.

가장 단순한 복구는 CocoaPods 재설치입니다.

sudo gem uninstall cocoapods
sudo gem install cocoapods -n /usr/local/bin
pod setup

Homebrew 기반으로 관리한다면 아래처럼 정리합니다.

brew reinstall ruby
gem install cocoapods
pod setup

팁: 회사/팀에서 Ruby 버전 고정이 필요하면 rbenvasdf로 버전 관리 후 pod를 설치하는 편이 재현성이 좋습니다.


해결 2) CocoaPods could not find compatible versions 의존성 충돌

증상 로그 예시

  • CocoaPods could not find compatible versions for pod "FirebaseCore"
  • Specs satisfying the ... dependency were found, but they required a higher minimum deployment target

원인

  • 플러그인들이 요구하는 iOS 최소 버전이 서로 다르거나
  • 이미 고정된 Podfile.lock이 새 플러그인 요구사항과 충돌하거나
  • 특정 Pod 버전이 사라졌거나 레포가 오래됨

해결 절차

  1. iOS 최소 타깃을 올립니다(특히 Firebase, 최신 SDK 계열).

ios/Podfile에서 아래처럼 조정합니다.

platform :ios, '13.0'
  1. 레포 갱신 및 락 재생성
cd ios
rm -f Podfile.lock
pod repo update
pod install
  1. 그래도 충돌이면, pod update로 특정 Pod만 갱신해 충돌 범위를 줄입니다.
cd ios
pod update FirebaseCore --verbose

주의: 무작정 pod update 전체를 돌리면 의존성이 연쇄적으로 올라가서 다른 오류가 추가될 수 있습니다. 충돌이 난 Pod부터 좁혀서 업데이트하세요.


해결 3) Unable to find a specification for ... Podspec을 못 찾음

증상 로그 예시

  • Unable to find a specification for 'XYZ' depended upon by 'Runner'
  • CDN: trunk Repo update failed

원인

  • CocoaPods spec repo가 오래되었거나
  • 네트워크/프록시로 CDN 접근이 막혔거나
  • 사내망에서 SSL 검사로 다운로드가 깨지는 경우

해결 절차

  1. 우선 repo 업데이트
cd ios
pod repo update
pod install --verbose
  1. CDN 이슈가 반복되면, 네트워크 환경(회사 VPN, 프록시, SSL 검사)을 점검합니다. 로그에 trunkCDN 타임아웃이 보이면 네트워크 계층 문제일 가능성이 큽니다.

  2. 사내 환경에서 반복된다면, 임시로 다른 네트워크에서 pod installPods/를 커밋하는 방식은 권장되지 않지만(재현성/용량 문제), 긴급 대응으로는 쓸 수 있습니다. 장기적으로는 네트워크 정책과 개발 환경을 정비해야 합니다.


해결 4) Sandbox is not in sync with the Podfile.lock 동기화 불일치

증상 로그 예시

  • The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.

원인

  • Pods/ 폴더와 Podfile.lock이 서로 다른 상태
  • 다른 브랜치에서 락 파일만 바뀌었거나, Pods 폴더만 남아있는 경우

해결 절차

가장 정석은 PodsPodfile.lock을 함께 정리하고 재설치입니다.

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

팀 운영 팁:

  • Podfile.lock은 보통 커밋하는 것이 재현성에 유리합니다.
  • 다만 플러그인 업데이트가 잦은 프로젝트는 “업데이트 정책”을 정하지 않으면 충돌이 반복됩니다.

해결 5) module not found, Non-modular header, Swift 모듈 임포트 실패

증상 로그 예시

  • Module 'xxx' not found
  • Include of non-modular header inside framework module
  • Swift compiler error가 Pods 쪽에서 발생

원인

  • 정적/동적 프레임워크 설정 충돌
  • use_frameworks!use_modular_headers! 조합 문제
  • 특정 플러그인이 모듈화 헤더를 요구하거나 반대로 깨뜨리는 경우

해결 절차

  1. Podfile에서 프레임워크 사용 방식을 명시합니다.

예시 1: 동적 프레임워크로 통일(플러그인 요구가 있을 때)

use_frameworks!

예시 2: 링크 방식 충돌을 줄이기 위해 static으로 지정

use_frameworks! :linkage => :static
  1. 모듈 헤더가 필요할 때
use_modular_headers!
  1. 변경 후에는 반드시 Pods 재설치
rm -rf ios/Pods ios/Podfile.lock
cd ios && pod install

팁: Firebase 계열과 일부 네이티브 SDK 조합에서 static 링크로 해결되는 경우가 많습니다. 반대로 어떤 SDK는 동적 프레임워크를 전제로 하기도 하니, 실패 로그에서 “어떤 모듈이 로드되지 않는지”를 기준으로 설정을 좁혀가세요.


해결 6) Xcode에서 Runner.xcworkspace가 아닌 Runner.xcodeproj로 빌드

증상

  • Xcode에서만 빌드 실패
  • Pods 관련 타깃을 못 찾거나, 링크 에러가 연쇄 발생

원인

CocoaPods를 쓰는 iOS 프로젝트는 워크스페이스를 통해 Pods 프로젝트가 함께 로드됩니다. Runner.xcodeproj를 열면 Pods가 빠져 빌드가 깨집니다.

해결 절차

  • Xcode에서 ios/Runner.xcworkspace를 열어 빌드합니다.
  • CI에서도 xcodebuild 대상이 워크스페이스인지 확인합니다.

CI 예시:

xcodebuild \
  -workspace ios/Runner.xcworkspace \
  -scheme Runner \
  -configuration Release \
  -sdk iphoneos \
  -destination 'generic/platform=iOS' \
  build

해결 7) Apple Silicon(M1/M2/M3)에서 아키텍처/시뮬레이터 관련 오류

증상 로그 예시

  • building for iOS Simulator, but linking in object file built for iOS
  • Undefined symbols for architecture arm64
  • 특정 Pod가 시뮬레이터 arm64를 지원하지 않음

원인

  • 시뮬레이터와 디바이스 빌드 산출물이 섞였거나
  • 오래된 Pod가 arm64 simulator를 제대로 지원하지 않거나
  • Xcode 빌드 설정에서 아키텍처 제외가 필요할 수 있음

해결 절차

  1. 우선 DerivedData 삭제 및 Pods 재설치로 “혼합 산출물”을 제거합니다.
rm -rf ~/Library/Developer/Xcode/DerivedData
rm -rf ios/Pods ios/Podfile.lock
cd ios && pod install
  1. 특정 Pod가 시뮬레이터 arm64에서만 깨진다면, 임시로 시뮬레이터에서 arm64 제외를 적용하는 방법이 있습니다. Podfile에 post_install 훅으로 설정을 넣습니다.
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
    end
  end
end

주의: 이 설정은 “근본 해결”이라기보다 호환성 문제를 우회하는 성격이 강합니다. 가능하면 문제가 되는 Pod/플러그인을 최신 버전으로 올려 arm64 simulator 지원을 확보하는 편이 좋습니다.


재발 방지 체크리스트(팀/CI 기준)

아래는 iOS 빌드 실패가 반복되는 팀에서 효과가 큰 운영 규칙입니다.

  1. flutter --version, xcodebuild -version, pod --version을 CI 로그에 항상 출력
  2. Podfile.lock 커밋 여부를 팀 정책으로 고정(커밋한다면 업데이트 절차도 문서화)
  3. 플러그인 업데이트 시에는 ios/Podfileplatform :ios 최소 버전도 함께 점검
  4. 빌드가 깨졌을 때 “무조건 클린”이 아니라, 어떤 단계에서 실패했는지 로그를 분리
    • pod install 단계 실패인지
    • Xcode 링크 단계 실패인지
    • 시뮬레이터 전용인지 디바이스 전용인지

빌드 이슈는 대부분 캐시/락/환경이 얽혀서 증상이 바뀌기 때문에, 원인 추적을 체계화해두면 해결 속도가 크게 빨라집니다. 캐시 충돌을 다루는 관점은 Next.js 14 RSC 캐시 꼬임과 stale 데이터 해결법 같은 글에서도 반복적으로 등장합니다.


결론: 로그를 7가지 유형으로 분류하면 해결이 빨라진다

Flutter iOS 빌드 실패는 “CocoaPods가 이상함”으로 뭉뚱그리기 쉽지만, 실제로는 다음 7가지로 거의 수렴합니다.

  1. Ruby/CocoaPods 실행 환경 문제
  2. Pod 버전 호환성 충돌
  3. Podspec repo 또는 네트워크 문제
  4. PodsPodfile.lock 동기화 불일치
  5. 모듈/헤더/프레임워크 설정 충돌
  6. 워크스페이스가 아닌 프로젝트로 빌드
  7. Apple Silicon 아키텍처 이슈

위 순서대로 좁혀가면, 불필요한 재설치와 시행착오를 크게 줄일 수 있습니다. 특히 ios/Pods, Podfile.lock, DerivedData를 정리하고 pod install을 “깨끗한 상태”에서 재현하는 것이 가장 강력한 1차 처치입니다.