Published on

Flutter iOS 빌드 No such module Flutter 해결

Authors

서버/웹 빌드가 아니라 iOS 네이티브 빌드에서 Flutter가 갑자기 사라진 것처럼 보이는 순간이 있습니다. Xcode에서 빌드하면 No such module 'Flutter'가 뜨고, Swift/ObjC 코드에서 import Flutter가 실패하거나, 플러그인 모듈들이 줄줄이 컴파일 에러를 내는 상황이죠.

이 에러는 “Flutter가 설치되지 않았다”라기보다는, iOS 프로젝트가 Flutter 프레임워크를 찾아갈 수 있는 경로/설정이 깨졌거나, CocoaPods가 생성해야 할 설정 파일이 누락되었거나, Xcode가 잘못된 빌드 산출물을 물고 있을 때 주로 발생합니다.

아래는 현장에서 가장 많이 맞닥뜨리는 원인들을 진단 순서대로 정리한 해결 가이드입니다.

에러의 정체: iOS가 Flutter 모듈을 못 찾는 이유

No such module 'Flutter'는 Swift 컴파일러가 Flutter 모듈을 import하려고 했지만, 빌드 설정(헤더/프레임워크 검색 경로, 모듈맵, xcconfig, CocoaPods 통합 결과물) 어디에서도 해당 모듈을 찾지 못한다는 뜻입니다.

대부분 다음 축 중 하나입니다.

  • CocoaPods 설치가 누락되었거나 Pods가 깨짐
  • .xcworkspace가 아니라 .xcodeproj로 열어 빌드함
  • ios/Flutter/Generated.xcconfig 또는 ios/Flutter/flutter_export_environment.sh가 없거나 오래됨
  • Podfile 설정/플랫폼 버전/정적-동적 링크 설정 문제
  • Xcode DerivedData/Pods 캐시 꼬임
  • Flutter SDK 경로/채널 변경 후 iOS 쪽이 갱신되지 않음

캐시가 원인인 경우도 많습니다. 캐시가 꼬여 “분명히 맞게 했는데도 안 되는” 유형은 Next.js에서 캐시가 엉키는 문제와 성격이 비슷합니다. 원리와 접근법은 동일하게 생성물 제거 후 재생성이 가장 안전합니다. 참고로 캐시 문제를 다루는 글은 이쪽도 함께 보면 도움이 됩니다: Next.js 14 App Router 캐시 꼬임 해결법

1단계: 가장 흔한 실수 — 워크스페이스로 열었는지 확인

CocoaPods를 쓰는 iOS 프로젝트는 반드시 .xcworkspace로 열어야 합니다.

  • 잘못된 경우: Runner.xcodeproj를 열고 빌드
  • 올바른 경우: Runner.xcworkspace를 열고 빌드

터미널에서 다음을 확인하세요.

ls ios
# Runner.xcworkspace 가 있어야 정상

없다면 CocoaPods가 정상 설치되지 않았을 가능성이 큽니다. 다음 단계로 바로 넘어가세요.

2단계: CocoaPods 재설치로 80% 해결

Flutter iOS 프로젝트에서 Pods는 Flutter 엔진 프레임워크와 플러그인들을 Xcode에 연결하는 역할을 합니다. Pods가 없거나 깨지면 Flutter 모듈을 못 찾게 됩니다.

아래를 순서대로 실행하세요.

flutter clean
rm -rf ios/Pods ios/Podfile.lock
rm -rf ios/.symlinks
rm -rf ios/Flutter/Flutter.framework ios/Flutter/Flutter.podspec

flutter pub get
cd ios
pod repo update
pod install
cd ..

그 다음 ios/Runner.xcworkspace로 열고 빌드합니다.

Apple Silicon(M1/M2/M3)에서 pod install이 이상할 때

루비/코코아팟 환경이 꼬여 pod install 자체가 실패하거나 비정상 동작하는 경우가 있습니다. 이때는 다음을 점검합니다.

  • pod --version 확인
  • sudo gem install cocoapods 대신 brew 기반으로 정리하거나, 프로젝트에서 Bundler 사용

Bundler를 쓰는 팀이라면 다음처럼 고정하는 것이 재현성에 좋습니다.

cd ios
bundle install
bundle exec pod install

3단계: Generated.xcconfig 누락/미생성 확인

Flutter는 iOS 빌드에 필요한 변수들을 Generated.xcconfig에 생성합니다. 이 파일이 없으면 Xcode가 Flutter SDK 경로 등을 몰라서 Flutter 모듈을 못 찾는 케이스가 생깁니다.

다음을 확인하세요.

ls ios/Flutter
# Generated.xcconfig 가 존재해야 함

없다면 보통 flutter pub get 또는 flutter build ios가 제대로 안 돌았거나, 파일이 Git에서 무시/삭제된 경우입니다.

재생성은 다음으로 해결되는 경우가 많습니다.

flutter pub get
flutter clean
flutter pub get

그래도 안 생기면 iOS 빌드 한 번을 강제로 돌려 생성시키세요.

flutter build ios --debug

4단계: Podfile 설정 점검(플랫폼 버전/프레임워크 설정)

특히 플러그인들이 Swift 기반이고, 프로젝트가 특정 링크 설정을 요구할 때 use_frameworks! 또는 use_modular_headers! 조합 때문에 모듈 import가 꼬일 수 있습니다.

기본에 가까운 Podfile 예시

아래는 Flutter 템플릿에 가까운 형태입니다(프로젝트마다 다를 수 있습니다).

platform :ios, '13.0'

# Flutter가 제공하는 pod helper
require File.expand_path(File.join('..', 'Flutter', 'podhelper'), __FILE__)

flutter_ios_podfile_setup

target 'Runner' do
  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end
end

use_frameworks!를 써야 하는 경우

일부 네이티브 SDK가 동적 프레임워크를 요구할 때 use_frameworks!를 넣기도 합니다. 하지만 이 설정은 플러그인 빌드 방식에 영향을 주어 No such module류 문제를 유발할 수 있습니다.

가능하면 다음 순서로 접근하세요.

  1. 우선 use_frameworks! 없이 빌드되는지 확인
  2. 필요하다면 use_frameworks! :linkage => :static처럼 정적 링크로 전환을 검토
  3. 특정 Pod만 프레임워크로 강제해야 한다면, 해당 SDK 문서의 권장 설정을 따름

설정을 바꿨다면 반드시 pod deintegrate 후 재설치가 안전합니다.

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

5단계: Xcode 빌드 설정에서 “검색 경로”가 망가졌는지 확인

팀에서 Xcode 설정을 직접 만지거나, .xcconfig를 커스텀했다면 Framework Search Paths 또는 Other Swift Flags가 꼬일 수 있습니다.

확인 포인트:

  • Xcode Build Settings에서 Base Configuration이 Flutter .xcconfig를 가리키는지
  • Runner 타깃의 Debug/Release가 각각 Flutter/Debug.xcconfig, Flutter/Release.xcconfig를 참조하는지

이 연결이 끊기면 Flutter 관련 변수들이 주입되지 않아 모듈을 못 찾습니다.

6단계: DerivedData 제거(캐시 꼬임 최종병기)

Xcode는 DerivedData에 많은 중간 산출물을 저장합니다. Flutter/Pods 구성이 바뀐 뒤에도 예전 산출물을 물고 있으면 No such module Flutter가 계속 재발할 수 있습니다.

다음으로 제거합니다.

rm -rf ~/Library/Developer/Xcode/DerivedData

그리고 Xcode를 완전히 종료했다가 다시 열고 빌드하세요.

빌드/캐시 문제는 CI에서도 자주 터집니다. CI가 점점 느려지고 이상해질 때 캐시를 무효화하는 접근은 GitHub Actions에서도 동일한 패턴으로 해결하는 경우가 많습니다: GitHub Actions 캐시 무효화로 빌드가 느릴 때

7단계: Flutter SDK 경로 변경/채널 변경 후 재동기화

Flutter SDK를 업데이트하거나 채널을 바꾼 뒤 iOS 쪽이 이전 경로를 바라보는 경우가 있습니다.

다음을 실행해 상태를 점검하세요.

flutter doctor -v
flutter --version

이후 iOS 관련 파일을 재생성하는 루틴을 한 번 더 수행합니다.

flutter clean
flutter pub get
cd ios
pod install
cd ..

8단계: “프로젝트가 Flutter 모듈을 임베드”하는 방식인지 확인

앱이 Flutter로만 구성된 일반적인 Runner 프로젝트인지, 아니면 기존 iOS 앱에 Flutter 모듈을 추가한 Add-to-App 구조인지에 따라 해결법이 달라집니다.

  • 일반 Flutter 앱: 위 단계대로 대부분 해결
  • Add-to-App: Flutter.xcframework 임베딩, 스크립트 페이즈, 빌드 설정이 더 복잡

Add-to-App이라면 다음을 추가로 확인해야 합니다.

  • iOS 앱 타깃의 Frameworks, Libraries, and Embedded Content에 Flutter 엔진이 올바르게 포함되는지
  • 빌드 스크립트가 flutter build ios-framework 산출물을 참조하는지

이 구조에서는 CocoaPods 대신 직접 프레임워크를 끌어오는 경우도 있어, “Pods 재설치”만으로는 해결되지 않을 수 있습니다.

재발 방지 체크리스트

팀에서 같은 문제가 반복된다면 아래를 권장합니다.

  • ios/Podfile.lock는 보통 커밋해서 Pod 버전을 고정(팀 정책에 따름)
  • 로컬에서만 재현되는 경우, DerivedData 제거를 표준 트러블슈팅에 포함
  • Xcode는 항상 Runner.xcworkspace로 열기
  • flutter clean을 남발하기보다는, 문제가 생겼을 때만 원인에 맞게 실행
  • CI에서는 캐시 키 전략을 명확히 하고, Pods/DerivedData 캐시가 문제를 만들면 과감히 무효화

빠른 해결 루틴(요약)

시간이 없을 때는 아래 순서로 실행하면 성공 확률이 높습니다.

flutter clean
rm -rf ios/Pods ios/Podfile.lock
rm -rf ios/.symlinks
rm -rf ~/Library/Developer/Xcode/DerivedData
flutter pub get
cd ios && pod install && cd ..
open ios/Runner.xcworkspace

여기까지 했는데도 동일하다면, 거의 항상 Podfile 커스텀 설정(프레임워크 링크 방식) 또는 Add-to-App 구조에서의 임베딩 경로 문제입니다. 그 경우에는 Podfile과 Xcode의 Build Settings에서 .xcconfig 연결 상태를 먼저 의심하고, 변경 이력을 기준으로 하나씩 되돌리며 확인하는 것이 가장 빠릅니다.