flutter pub upgrade --major-versions 함부로 치면 안 되는 이유
발단: "패키지 업데이트나 해볼까"
리팩토링 작업을 하고 있었는데, pubspec.lock이 손상되는 바람에 flutter pub get을 다시 돌려야 했습니다.
Error on line 1054, column 7 of pubspec.lock:
The name should be shared_preferences
간단하게 lock 파일 삭제하고 재생성하면 되는 거였습니다.
rm pubspec.lock
flutter pub get
여기까진 좋았어요. 그런데 이김에 패키지도 좀 정리하자는 생각이 들었습니다.
flutter pub upgrade --major-versions
이걸 치는 순간부터 지옥이 시작됐습니다.
1차 폭발: Dart SDK 버전 충돌
The current Dart SDK version is 3.7.2.
Because shared_preferences 2.5.4 requires SDK version ^3.9.0,
shared_preferences ^2.5.4 is forbidden.
shared_preferences 최신 버전이 Dart 3.9.0을 요구하는데, 제 환경은 Dart 3.7.2였습니다.
이때 선택지가 두 개였거든요.
A) Flutter SDK를 3.41.1로 올린다 — Dart 3.9.0+ 포함 B) shared_preferences를 3.7.2에 맞는 버전으로 내린다
프로덕션 앱이니까 안전하게 B를 선택했습니다.
flutter pub add shared_preferences:^2.5.3
근데 하나 내리니까 다른 데서 또 터집니다.
2차 폭발: flutter_lints도 호환 안 됨
The current Dart SDK version is 3.7.2.
Because flutter_lints 6.0.0 requires SDK version ^3.8.0,
flutter_lints ^6.0.0 is forbidden.
flutter_lints도 최신 버전이 Dart 3.8.0을 요구합니다. --major-versions가 모든 패키지를 최신으로 올려버렸으니 당연한 결과죠.
flutter pub add flutter_lints:^5.0.0
이것도 내리고 나서야 겨우 flutter pub get이 성공했습니다.
교훈: --major-versions가 하는 일을 정확히 알아야 한다
flutter pub upgrade # 현재 제약 범위 내에서 업데이트 (안전)
flutter pub upgrade --major-versions # 메이저 버전까지 전부 올림 (위험!)
--major-versions는 pubspec.yaml의 버전 제약 자체를 바꿔버립니다.
# before
shared_preferences: 2.5.3
# after (--major-versions 실행 후)
shared_preferences: ^2.5.4 # Dart 3.9.0 필요!
flutter_lints: ^6.0.0 # Dart 3.8.0 필요!
현재 Dart SDK와 호환되는지 확인하지 않고 무조건 최신으로 올리기 때문에, SDK 버전이 낮으면 빌드가 바로 깨집니다.
안전한 업데이트 순서
제가 겪고 나서 정리한 순서입니다.
# 1. 먼저 뭐가 오래됐는지 확인만 한다
flutter pub outdated
# 2. 현재 SDK 범위 내에서만 업데이트
flutter pub upgrade
# 3. 메이저 업데이트가 필요하면 패키지 하나씩 확인
# pub.dev에서 Dart SDK 요구 버전 체크 후 수동으로
flutter pub add shared_preferences:^2.5.3
# 4. 절대 먼저 치지 말 것
# flutter pub upgrade --major-versions ← 이거 함부로 ㄴㄴ
핵심은 flutter pub outdated로 먼저 확인하고, 하나씩 올리는 것입니다. 한 번에 다 올리면 어디서 터졌는지 찾기가 어렵습니다.
번외: Flutter SDK 자체를 올릴 때 주의할 것
만약 "그냥 Flutter를 최신으로 올리자"고 결정했다면, 그것도 만만치 않습니다.
저는 아직 3.7.x에 머물러 있는데, 최신이 3.41.x이라 점프가 너무 큽니다. 검색해보니 주요 Breaking Changes가 이렇게 쌓여 있었습니다.
iOS — UIScene 마이그레이션 (필수)
iOS 27부터 UIScene을 사용하지 않는 앱은 아예 실행이 안 됩니다. Flutter 3.38부터 UIScene 라이프사이클을 지원하며, 3.41에서는 기본값입니다.
마이그레이션이 필요한 부분:
- AppDelegate에서 플러그인 등록을 didInitializeImplicitFlutterEngine으로 이동
- Info.plist에 UIApplicationSceneManifest 추가
- applicationDidBecomeActive 같은 앱 라이프사이클 코드가 있다면 SceneDelegate로 이동
Flutter CLI가 자동 마이그레이션을 시도해주긴 합니다.
flutter build ios # 자동 마이그레이션 시도
# 성공하면: "Finished migration to UIScene lifecycle"
Android — AGP 9 업데이트 금지
Flutter 3.41 기준으로 AGP(Android Gradle Plugin) 9는 아직 지원 안 됩니다. Android Studio가 AGP 업데이트를 권유해도 무시해야 합니다.
또한 Flutter 3.38부터 Android 15 타겟 시 16KB 페이지 사이즈 지원이 필요하며, NDK r28이 기본값으로 변경되었습니다.
Material 3 마이그레이션
useMaterial3: true가 기본값이 되면서, 기존 Material 2 기반 UI가 미묘하게 달라질 수 있습니다. 특히 ElevatedButton, Card, Dialog 같은 위젯의 기본 스타일이 바뀝니다.
한국 개발자 특별 주의: flutter_naver_map
네이버 맵처럼 한국 패키지는 업데이트가 느린 경우가 많습니다.
flutter_naver_map: 1.3.1 # 최신 Dart SDK와 호환되는지 꼭 확인
Flutter SDK를 올렸는데 네이버 맵이 호환 안 되면, 지도 기능 전체가 빌드 실패합니다. pub.dev에서 패키지의 Dart SDK 요구 버전을 꼭 확인하세요.
같은 이유로 location, geolocator, permission_handler 같은 네이티브 의존성이 강한 패키지도 주의가 필요합니다.
제가 정리한 업그레이드 체크리스트
□ flutter pub outdated로 현황 파악
□ 패키지별 Dart SDK 요구 버전 확인 (pub.dev)
□ flutter_naver_map 등 한국 패키지 호환 여부 확인
□ flutter pub upgrade (범위 내만)
□ 필요한 패키지만 수동으로 버전 지정
□ iOS: UIScene 마이그레이션 여부 확인
□ Android: AGP 버전 유지, NDK r28 확인
□ flutter build ios --debug 테스트
□ flutter build apk --debug 테스트
□ 실기기에서 주요 기능 동작 확인
정리
상황 해야 할 것 하면 안 되는 것
| 패키지 업데이트 | flutter pub outdated 먼저 확인 | --major-versions 바로 실행 |
| SDK 충돌 | 패키지를 현재 SDK에 맞게 다운그레이드 | 검증 없이 Flutter SDK 올리기 |
| pubspec.lock 손상 | 삭제 후 flutter pub get | lock 파일 수동 편집 |
| Flutter SDK 업그레이드 | 별도 브랜치에서 충분한 시간 확보 | 프로덕션 직전에 업그레이드 |
| iOS 빌드 실패 | UIScene 마이그레이션 확인 | AppDelegate 코드 그대로 방치 |
결국 핵심은 **"한 번에 다 바꾸지 말고, 하나씩 바꾸면서 빌드 확인"**입니다. --major-versions 한 줄이 반나절을 날릴 수 있다는 걸 몸으로 배웠습니다.
이 글은 에어컨 서비스 플랫폼 "코너 파트너스" 앱 개발 과정에서 작성되었습니다.
