Flutter 앱을 TestFlight에 올렸는데 실기기에서 모든 API 요청이 실패하는 경우, --dart-define으로 API URL이 주입되지 않아서 앱이 localhost로 요청을 보내고 있는 게 원인일 수 있다.
증상
- 시뮬레이터에서는 정상 동작 (로컬 서버에 연결되니까)
- TestFlight 빌드(실기기)에서는 로그인, API 호출 모두 실패
- 서버 로그에 해당 요청이 아예 안 찍힘 → 클라이언트가 서버에 요청 자체를 안 하고 있음
원인
Flutter에서 환경별 API URL을 --dart-define으로 주입받는 패턴을 쓰는 경우, 빌드 명령에 이 인자를 빠뜨리면 코드 내 기본값이 사용된다.
// environment.dart
static const String apiUrl = String.fromEnvironment(
'API_URL',
defaultValue: 'http://localhost:3000', // dart-define 없으면 이 값 사용
);
로컬 개발 시에는 flutter run으로 실행하면서 --dart-define을 넘기거나, 아예 기본값이 localhost여도 로컬 서버가 떠 있어서 동작한다.
그런데 flutter build ipa를 실행할 때 --dart-define을 빠뜨리면 릴리즈 빌드에도 localhost가 그대로 들어간다.
확인 방법
Makefile이나 빌드 스크립트를 열어서 flutter build ipa 명령에 --dart-define이 있는지 확인한다.
# 잘못된 예시
build-ipa:
flutter build ipa --release \
--export-options-plist=$(EXPORT_OPTIONS)
# 올바른 예시
build-ipa:
flutter build ipa --release \
--dart-define=API_URL=https://api.example.com \
--export-options-plist=$(EXPORT_OPTIONS)
수정
빌드 명령에 --dart-define=API_URL=을 추가한다.
build-ipa:
flutter build ipa --release \
--dart-define=API_URL=https://api.example.com \
--export-options-plist=$(EXPORT_OPTIONS)
testflight: build-ipa
xcrun altool --upload-app \
--type ios \
--file "build/ios/ipa/app.ipa" \
--apiKey $(API_KEY) \
--apiIssuer $(API_ISSUER)
dart-define을 여러 개 쓰는 경우
환경 변수가 여러 개라면 각각 --dart-define을 반복해서 추가한다.
build-ipa:
flutter build ipa --release \
--dart-define=API_URL=https://api.example.com \
--dart-define=GOOGLE_MAPS_KEY=AIzaSy... \
--dart-define=ENVIRONMENT=production \
--export-options-plist=$(EXPORT_OPTIONS)
주의사항
--dart-define에 넣는 값은 빌드 시점에 바이너리에 포함된다. API 키처럼 민감한 값을 여기에 넣으면 앱 바이너리에서 추출 가능하다. 진짜 비밀 값은 서버에서 관리하고, 클라이언트에는 공개 키 또는 공개 URL 정도만 넣는 게 좋다.
정리
| 상황 | API URL |
|---|---|
flutter run (로컬) | --dart-define 없으면 defaultValue 사용 |
flutter build ipa | --dart-define 없으면 defaultValue 사용 |
| TestFlight / AppStore | Makefile에서 --dart-define 넣어야 production URL 사용 |
TestFlight 빌드는 결국 릴리즈 빌드이므로, Makefile이나 CI 스크립트에서 --dart-define을 관리하고 빠뜨리지 않도록 주의한다.

💬 댓글
비밀번호를 기억해두면 나중에 내 댓글을 삭제할 수 있어요.