Flutter 3.47 iOS 업그레이드는 운영 빌드 노드를 바로 덮어쓰지 말고, 이번 주에는 격리된 원격 맥에서 업그레이드한 뒤 서명·Archive·CI 검증을 끝내는 방식으로 진행해야 합니다. CocoaPods 설정도 처음부터 전부 삭제하지 말고, 호환되지 않는 플러그인의 회귀 경로로 남겨야 합니다.
이 글은 원생 iOS 플러그인, 여러 Flavor, 사용자 정의 Target을 포함한 Flutter 프로젝트를 담당하는 개발자를 위한 내용입니다. 원격 맥 CI 노드를 관리하거나 Flutter add-to-app 구조를 유지하는 엔지니어도 같은 기준으로 판단할 수 있습니다.
마지막 업데이트: 2026년 8월 21일. Flutter 안정 버전과 기본 의존성 정책은 공식 안정 버전 목록, Archive와 내보내기 절차는 공식 배포 문서를 기준으로 확인했습니다.
먼저 프로젝트의 마이그레이션 경로를 분류합니다
Flutter 공식 안내에 따르면 Flutter 3.47은 2026년 8월 21일 기준 안정 버전 목록에 포함되어 있습니다. 또한 Flutter 3.44부터 iOS와 macOS 원생 의존성의 기본 관리 경로가 Swift Package Manager로 바뀌었습니다. 다만 모든 플러그인이 즉시 전환되는 것은 아니므로, 프로젝트 구조에 따라 처리 방식이 달라집니다.
다음 조건으로 첫 분류를 진행합니다.
- 기본 Runner 구조이고 원생 수정이 거의 없다면 표준 자동 마이그레이션 경로를 선택합니다.
- Podfile과 원생 플러그인이 많다면 Swift Package Manager와 CocoaPods의 혼합 구성을 우선 검증합니다.
- Flavor, 사용자 정의 Target, 공유 Scheme이 있다면 구성별로 별도 검증합니다.
- add-to-app 프로젝트라면 순수 Flutter 앱과 같은 방식으로 덮어쓰지 않습니다.
- CI 노드라면 기존 생산 노드가 아닌 별도 원격 맥에서 환경 재현부터 시작합니다.
업그레이드 전에 다음 파일과 증거를 별도 브랜치에 보관합니다.
pubspec.lock과 각 네이티브 의존성 잠금 파일ios/Podfile,Podfile.lock, Xcode 프로젝트 설정- 공유 Scheme과 Build Configuration
- 기존 빌드 로그, Archive 경로, 내보내기 설정
- 사용 중인 Flutter, Xcode, 서명 인증서와 프로비저닝 프로파일의 식별 정보
버전 숫자와 도구 조합은 프로젝트마다 다르므로, 문서에 적힌 예시를 그대로 복사하기보다 현재 생산 노드의 실제 출력과 비교해야 합니다.
표준 프로젝트는 생성된 변경을 관찰하며 통과시킵니다
기본 템플릿에 가까운 프로젝트라도 업그레이드 직후 파일을 수동으로 덮어쓰면 필요한 변경과 불필요한 변경을 구분하기 어렵습니다. 먼저 새 브랜치에서 Flutter와 패키지 잠금 상태를 고정하고, Xcode 프로젝트의 변경 내용을 버전 관리 도구로 비교합니다.
관찰 대상은 다음과 같습니다.
- Swift Package Manager 의존성이 Xcode 프로젝트에 어떤 방식으로 연결되는지
- Flutter Framework 준비 스크립트가 기존 실행 순서와 충돌하지 않는지
- 생성 파일이 프로젝트 저장소에 포함되어야 하는지
- 공유 Scheme이 다른 개발자와 CI에서 동일하게 열리는지
- 시뮬레이터 실행과 실제 기기 빌드가 모두 같은 의존성 상태를 사용하는지
표준 프로젝트의 최소 검증 순서는 다음과 같습니다.
- 업그레이드 전 커밋에서 Debug 실행과 테스트 결과를 저장합니다.
- 격리 브랜치에서 Flutter 3.47과 의존성 잠금 상태를 적용합니다.
- Xcode 프로젝트와 생성 파일의 변경 내용을 비교합니다.
- 시뮬레이터 실행 후 실제 기기용 서명 빌드를 진행합니다.
- Archive와 내보내기를 실행하고 이전 로그와 산출물 경로를 비교합니다.
- 통과한 변경만 검토 가능한 커밋으로 분리합니다.
이 과정에서 Debug 실행만 성공했다면 마이그레이션 완료로 기록하지 않습니다. iOS 배포에서 필요한 Archive와 서명 내보내기는 별도의 자격 증명과 Build Configuration을 사용하기 때문입니다. Xcode의 Archive 및 내보내기 안내도 함께 확인해야 합니다.
CocoaPods 혼합 구성은 실패가 아니라 임시 경로입니다
Flutter 3.44 이후 Swift Package Manager가 기본 경로가 되었지만, 공식 안내는 아직 이를 지원하지 않는 의존성에 CocoaPods 회귀 경로를 남깁니다. 따라서 Podfile이 존재한다는 이유만으로 마이그레이션 실패라고 결론 내릴 수 없습니다.
플러그인마다 다음 항목을 기록합니다.
- 의존성이 Swift Package Manager와 CocoaPods 중 어느 경로로 해석되었는지
- 실제 Xcode 컴파일에 포함된 원생 산출물
- 최소 iOS 버전과 필요한 빌드 설정
- Debug, 실제 기기, Release Archive에서의 결과
- 동일 플러그인이 캐시 삭제 후에도 같은 방식으로 해석되는지
의사결정은 다음 조건으로 나눕니다.
- 모든 원생 플러그인이 Swift Package Manager로 해석되고 Release Archive까지 통과하면 새 경로로 전환합니다.
- 일부 플러그인만 지원하지 않지만 CocoaPods 혼합 빌드가 안정적이면 두 경로를 유지합니다.
- 특정 플러그인이 서명이나 Archive에서만 실패하면 플러그인을 교체하거나 업그레이드를 보류합니다.
- 의존성 해석이 실행마다 달라지면 생산 노드 전환을 중단하고 잠금 상태와 캐시를 먼저 고정합니다.
공식 Swift Package Manager 애플리케이션 개발자 안내는 프로젝트 설정과 전환 조건을 확인하는 기준으로 사용할 수 있습니다. 특정 플러그인의 호환 목록은 일반화하지 말고 해당 플러그인의 최신 문서와 실제 빌드 로그로 판단해야 합니다.
다중 Flavor와 사용자 정의 Target은 구성별 증거가 필요합니다
다중 Flavor 프로젝트에서 기본 Runner만 실행되는 것은 부분 성공에 불과합니다. staging과 production이 서로 다른 Scheme, Bundle Identifier, 서명 설정, API 환경, Build Configuration을 사용한다면 각 구성의 결과를 따로 남겨야 합니다.
확인 순서는 다음과 같습니다.
- 각 Flavor의 Scheme이 올바른 Build Configuration을 선택하는지 확인합니다.
- Swift Package Manager 의존성이 사용자 정의 Target에도 연결되는지 검사합니다.
- 준비 스크립트가 Debug와 Release에서 동일한 순서로 실행되는지 확인합니다.
- 각 Flavor에서 단위 테스트와 실제 기기 실행을 진행합니다.
- staging과 production을 각각 Archive하고 내보냅니다.
- 산출물 이름, Bundle Identifier, 서명 상태, 생성 경로를 기록합니다.
특히 사용자 정의 Target이 새 패키지 의존성을 참조하지 못하면 기본 앱은 빌드되지만 특정 Flavor의 Archive만 실패할 수 있습니다. 이때 “Runner가 성공했다”는 로그는 production 전환의 증거가 아닙니다. Scheme 설정 파일, 전체 빌드 로그, 실제 산출물을 함께 보관해야 합니다.
add-to-app은 기존 통합 방식을 겹쳐 적용하지 않습니다
add-to-app은 Flutter 모듈이 이미 존재하는 원생 iOS 주 프로젝트에 연결되는 구조입니다. 순수 Flutter 앱처럼 생성 파일을 교체하거나 기존 Framework 삽입 설정을 제거하면 원생 화면에서 Flutter 모듈이 시작되지 않을 수 있습니다.
먼저 원생 주 프로젝트에서 다음을 확인합니다.
- Swift Package Manager 또는 CocoaPods로 선언된 기존 패키지
- Flutter 모듈 초기화 시점과 엔진 생성 방식
- Flutter 자원 묶음의 복사 단계
- Debug, staging, Release별 모듈 경로와 설정
- 기존 Framework 삽입 방식과 새 의존성 연결 방식의 중복 여부
검증은 최소 세 가지 증거로 구성합니다.
- 원생 화면에서 Flutter 모듈을 실제로 한 번 시작한 로그
- Release 구성의 빌드와 Archive 결과
- 새 통합을 제거하고 이전 통합 방식으로 복구하는 리허설
Flutter add-to-app iOS 프로젝트 설정 문서는 유지 관리 시 확인할 공식 기준입니다. 기존 통합을 백업하지 않은 상태에서 새 방식만 추가하는 것은 되돌리기 어려운 변경이므로 피해야 합니다.
원격 맥 CI 노드는 그래픽 세션 밖에서 검증합니다
원격 맥을 Flutter iOS 빌드 노드로 사용할 때는 화면 공유 세션에서 성공한 결과만 믿으면 안 됩니다. CI는 보통 SSH 비대화형 세션이나 별도 실행 계정에서 동작하므로 환경 변수, 키체인 접근, 캐시 경로가 달라질 수 있습니다.
다음 다섯 단계로 운영 전환을 검사합니다.
- Flutter, Xcode, 패키지 잠금 파일과 빌드 스크립트를 별도 노드에 고정합니다.
- 캐시를 비운 깨끗한 빌드와 캐시를 사용하는 반복 빌드를 각각 실행합니다.
- SSH 비대화형 세션에서 인증 정보, 환경 변수, 키체인 접근을 확인합니다.
- 실제 기기 서명, Archive, 내보내기를 CI 명령으로 실행합니다.
- 노드를 재시작한 뒤 캐시, 권한, 실행 계정, 작업 디렉터리가 복구되는지 확인합니다.
서명 인증서와 프로비저닝 프로파일은 파일이 존재하는지만 보지 말고, CI 실행 계정이 실제로 사용할 수 있는지 확인해야 합니다. 인증서 공유와 관리 방식은 공식 서명 인증서 문서를 기준으로 검토합니다.
이번 주 전환 여부는 조건 목록으로 결정합니다
다음 체크리스트를 별도 이슈나 배포 기록에 복사해 사용합니다. 각 항목에 실제 로그나 산출물 경로를 연결할 수 있을 때만 통과로 표시해야 합니다.
- [ ] Flutter 3.47과 Xcode 버전, 패키지 잠금 상태를 격리된 원격 맥에 고정했습니다.
- [ ] 업그레이드 전 커밋의 Debug 실행과 테스트 결과를 보관했습니다.
- [ ] Swift Package Manager와 CocoaPods의 플러그인별 의존성 해석 결과를 기록했습니다.
- [ ] 시뮬레이터 실행과 실제 기기 서명 빌드를 모두 완료했습니다.
- [ ] 모든 Flavor와 사용자 정의 Target에서 테스트와 Release 빌드를 실행했습니다.
- [ ] staging과 production의 Archive 및 서명된 내보내기를 각각 확인했습니다.
- [ ] add-to-app 원생 화면에서 Flutter 모듈을 시작했습니다.
- [ ] SSH 비대화형 세션에서도 환경 변수와 인증 정보가 정상적으로 전달되었습니다.
- [ ] 깨끗한 빌드와 캐시 빌드가 같은 의존성 결과를 만들었습니다.
- [ ] 노드 재시작 후 캐시, 권한, 서명 접근이 복구되었습니다.
- [ ] 이전 커밋과 기존 통합 방식으로 되돌리는 리허설을 완료했습니다.
판단 조건은 다음과 같습니다.
- 모든 항목이 통과하면 새 구성을 생산 노드에 단계적으로 적용합니다.
- CocoaPods 플러그인이 남아 있지만 혼합 빌드가 반복적으로 통과하면 두 경로를 유지한 채 전환합니다.
- Flavor, 사용자 정의 Target, add-to-app 중 하나라도 Archive나 서명에서 실패하면 생산 전환을 중지합니다.
- SSH 세션이나 재시작 뒤 서명과 캐시가 사라지면 현재 노드를 유지하고 환경 고정부터 다시 진행합니다.
- 통과 증거를 재현할 수 없으면 업그레이드 브랜치를 폐기하지 말고 이전 커밋으로 되돌릴 수 있는 상태를 유지합니다.
이 도구는 “Swift Package Manager로 바꿀 것인가”만 묻지 않습니다. 실제 판단 기준은 의존성 해석이 반복 가능하고, 모든 배포 구성이 서명된 산출물을 만들며, 장애 때 이전 상태로 돌아갈 수 있는가입니다.
독립 원격 맥이 필요한 경우의 운영 선택
현재 방식이 단일 생산 맥에 업그레이드와 빌드를 동시에 맡긴 구조라면 장애 범위가 큽니다. 업그레이드 중 캐시가 바뀌고, 인증서 접근이 깨지며, production Flavor만 뒤늦게 실패할 수 있습니다. 로컬 장비만 사용하는 방식도 장시간 Archive와 재시작 복구 검증을 반복하기 어렵습니다.
따라서 별도 장비를 구매하기 전에 한 번의 출시 주기 동안 독립된 원격 맥을 테스트 노드로 두는 방식이 현실적입니다. NodeMini의 원격 맥 개발 환경 구성 안내를 참고해 현재 Flutter iOS 파이프라인을 복제하고, 먼저 깨끗한 빌드·캐시 빌드·서명·Archive·재시작 복구를 기록하면 됩니다.
장기적으로 항상 무거운 빌드를 실행하고 물리 기기 연결이나 고정 장비가 필요하다면 자체 Mac 구매가 더 적합할 수 있습니다. 반대로 업그레이드 검증, 임시 CI 노드, 출시 기간의 병렬 빌드가 목적이라면 현재 생산 맥의 단일 장애점과 로컬 장비의 유지 비용을 피하면서 NodeMini의 원격 맥을 임대하는 편이 운영상 유연합니다. 맥 미니 임대 선택지를 검토하되, 체크리스트가 통과된 뒤 장기 보유 여부를 결정하는 순서가 안전합니다.
자주 확인하는 마이그레이션 판단
Flutter 3.47에서 Swift Package Manager 전환은 의무인가요?
의무적인 일괄 전환으로 처리하면 안 됩니다. Flutter 3.44부터 기본 경로가 Swift Package Manager로 바뀌었지만, 지원하지 않는 플러그인은 CocoaPods 회귀 경로를 사용할 수 있습니다. 프로젝트 전체를 한 번에 바꾸기보다 플러그인별 해석 결과와 Release Archive를 확인한 뒤 전환 범위를 정해야 합니다.
CocoaPods를 남겨도 업그레이드가 실패한 것인가요?
그렇지 않습니다. 아직 Swift Package Manager를 지원하지 않는 플러그인이 있다면 CocoaPods를 남긴 혼합 구성이 정상적인 대응일 수 있습니다. 다만 Podfile의 존재만 확인해서는 부족합니다. 실제 원생 산출물, 최소 운영체제 조건, 캐시 삭제 후 재현성까지 확인해야 합니다.
여러 Flavor에서 새 의존성 연결을 어떻게 확인하나요?
각 Flavor의 Scheme과 Build Configuration을 따로 실행해야 합니다. 기본 Runner의 Debug 결과만으로는 production Archive 성공을 증명할 수 없습니다. staging과 production에서 테스트, 실제 기기 빌드, Archive, 서명된 내보내기를 수행하고 로그와 산출물 경로를 저장해야 합니다.
add-to-app 프로젝트의 핵심 위험은 무엇인가요?
기존 원생 주 프로젝트의 통합 방식을 새 방식과 무심코 겹치는 것이 가장 큰 위험입니다. 패키지 의존성, 모듈 초기화, 자원 묶음, 구성별 설정을 확인하고 원생 화면에서 Flutter 모듈을 실행해야 합니다. 이전 통합으로 복구할 수 있는지도 별도로 시험해야 합니다.
원격 맥 CI에서 Archive와 서명을 어떻게 확인하나요?
화면 공유가 아닌 SSH 비대화형 실행으로 깨끗한 빌드, 캐시 빌드, 실제 기기 서명, Archive, 내보내기를 순서대로 실행합니다. 인증 정보와 환경 변수가 실행 계정에 전달되는지 확인하고, 노드 재시작 후에도 캐시와 서명 접근이 유지되는지 검증해야 합니다.
이번 업그레이드의 안전한 종료 조건은 Flutter 3.47을 설치했다는 사실이 아니라, 프로젝트의 모든 배포 구성과 원생 통합이 반복 가능하게 빌드되고 이전 상태로 복구된다는 증거입니다. 별도 테스트 맥이 없다면 한 출시 주기 동안 독립된 원격 맥에 기존 파이프라인을 복제하고, 이 조건을 모두 통과한 뒤 생산 노드를 유지하거나 확장하거나 해제하는 결정을 내려야 합니다.