guricode

[트러블슈팅] iOS와 Android 동시 배포 완전 정리 본문

앱/Flutter&Dart

[트러블슈팅] iOS와 Android 동시 배포 완전 정리

agentrakugaki 2025. 10. 8. 22:38

이 글은 Flutter 앱 "자취의 정석"을 iOS와 Android에 배포하며 겪은 문제와 해결 과정을 정리한 것이다. 앱은 Firestore와 Riverpod을 기반으로 한 지역 커뮤니티 + 미션형 성장 시스템이다.


1. 배포 전 필수 사이트

플랫폼 사이트 용도
iOS App Store Connect 앱 등록 및 심사 관리
iOS Apple Developer 인증서, 키, 프로파일 관리
iOS TestFlight iOS 앱 테스트 배포
Android Google Play Console 앱 등록, 테스트, 프로덕션 배포
공통 Firebase Console Firestore, Auth, Analytics 설정
공통 Flutter 공식 문서 빌드 및 배포 가이드

2. iOS 배포 과정

1단계. 빌드 준비

flutter build ipa --release

Xcode를 열고 Product → Archive → Organizer에서 Upload 진행.

2단계. 오류

Module 'cloud_firestore' not found

Podfile.lock과 CocoaPods 환경 불일치.

cd ios
rm -rf Pods Podfile.lock
pod repo update
pod install
cd ..
flutter clean
flutter pub get

3단계. Keychain 암호 문제

Keychain Access → login → 잠금 해제 후 비밀번호 재설정.

4단계. 빌드 서비스 오류

unable to initiate PIF transfer session (operation in progress?)
sudo xcodebuild -runFirstLaunch

5단계. 앱 아이콘 등록

flutter_launcher_icons:
  android: true
  ios: true
  image_path: "assets/icon/icon.png"
dart run flutter_launcher_icons

3. Android 배포 과정

1단계. keystore 생성

keytool -genkey -v -keystore my-release-key.keystore -alias release -keyalg RSA -keysize 2048 -validity 10000

2단계. key.properties 생성

storeFile=/Users/username/keystore/my-release-key.keystore
storePassword=비밀번호
keyAlias=release
keyPassword=비밀번호

3단계. build.gradle.kts 수정

val keystoreProperties = Properties().apply {
  val f = rootProject.file("android/key.properties")
  if (f.exists()) load(FileInputStream(f))
}

signingConfigs {
  create("release") {
    keyAlias = keystoreProperties["keyAlias"] as String?
    keyPassword = keystoreProperties["keyPassword"] as String?
    storeFile = (keystoreProperties["storeFile"] as String?)?.let { file(it) }
    storePassword = keystoreProperties["storePassword"] as String?
  }
}

4단계. versionCode 중복 문제

Play Console에서 "버전코드 1이 이미 사용됨" 오류 발생 시

version: 1.0.0+2

로 수정 후 재빌드

flutter clean
flutter pub get
flutter build appbundle --release

4. 배포 트랙 비교

트랙 특징 심사 여부
내부 테스트 즉시 배포 가능 심사 없음
비공개 테스트 특정 테스터 대상 심사 없음
프로덕션 정식 공개 심사 필요

같은 빌드는 재사용할 수 없으므로 항상 versionCode를 +1 증가시켜야 한다.


5. 빌드 경고 해결

source value 8 is obsolete

Java 버전을 17로 올려 해결.

compileOptions {
  sourceCompatibility = JavaVersion.VERSION_17
  targetCompatibility = JavaVersion.VERSION_17
  isCoreLibraryDesugaringEnabled = true
}
dependencies {
  coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.2")
}

6. App Store와 Play Store 심사 팁

  • iOS는 심사 속도가 느리므로 사전 심사용 TestFlight를 먼저 활용한다.
  • Android는 버전코드 충돌이 자주 발생하므로 빌드 번호를 명시적으로 관리한다.
  • 앱 설명은 기능 중심으로, 키워드는 10개 이하로 간결하게 정리한다.
  • 스크린샷은 기기별 크기별로 1242x2688 이상 해상도로 준비한다.
  • 아이콘은 1024x1024 PNG 투명 배경 없이 준비한다.

7. 전체 요약

플랫폼 문제 해결
iOS Podfile 불일치 pod install 재실행
iOS 빌드 서비스 충돌 xcodebuild -runFirstLaunch
Android keystore NullPointer 경로 확인 및 key.properties 수정
Android 버전코드 중복 pubspec.yaml 버전 +1
Android Java 8 경고 JavaVersion 17로 변경

8. 배운 점

  • 빌드 실패의 대부분은 환경 설정 오류에서 비롯된다.
  • iOS는 Xcode 캐시, Android는 Gradle 서명 충돌이 핵심 이슈이다.
  • 버전 관리와 서명 파일 관리가 성공적인 배포의 핵심이다.
  • 환경을 정리하고 명령어 단계를 문서화하는 습관이 필요하다.

이 글이 Flutter로 앱을 개발하고 실제 스토어 배포를 준비하는 개발자에게 실질적인 도움이 되길 바란다.

참고 사이트