![[Flutter + Firebase로 북마크 앱 만들기 #6] Android 앱 빌드 및 Play Store 배포 준비](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BFlutter%2520%252B%2520Firebase%25EB%25A1%259C%2520%25EB%25B6%2581%25EB%25A7%2588%25ED%2581%25AC%2520%25EC%2595%25B1%2520%25EB%25A7%258C%25EB%2593%25A4%25EA%25B8%25B0%2520%25236%255D%2520Android%2520%25EC%2595%25B1%2520%25EB%25B9%258C%25EB%2593%259C%2520%25EB%25B0%258F%2520Play%2520Store%2520%25EB%25B0%25B0%25ED%258F%25AC%2520%25EC%25A4%2580%25EB%25B9%2584%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3DGyeongwon%27s%2520blog&w=2048&q=75)
📌 시리즈 목차
🎯 이번 글에서 다룬 내용
- Android 앱 빌드 환경 설정
- 앱 아이콘 및 메타데이터 설정
- Keystore 생성 및 앱 서명
- Release 빌드 (APK/AAB)
- Firebase 설정 업데이트
- 트러블슈팅 (실전 경험담)
📱 목표: Play Store 배포 준비 완료
최종 산출물:
- ✅ Release APK (테스트용)
- ✅ Release AAB (Play Store 업로드용)
- ✅ 서명된 빌드
- ✅ 에뮬레이터 테스트 완료
1️⃣ Android 빌드 준비
앱 기본 정보 결정
앱 이름
LinkOn
Application ID (패키지명)
com.doythan.bookmarkmanager
중요:
- 한 번 정하면 변경 불가능!
com.example
은 Play Store 업로드 불가
- 형식:
com.[개발자명].[앱명]
버전 정보
versionCode: 1
versionName: 1.0.0
2️⃣ 앱 아이콘 설정
flutter_launcher_icons 패키지 설치
flutter pub add --dev flutter_launcher_icons
아이콘 파일 준비
# 폴더 생성
mkdir -p assets/icon
# 512x512 PNG 아이콘 준비
# (Figma, Canva, AI 도구 등으로 제작)
pubspec.yaml 설정
위치:
pubspec.yaml
# 파일 끝에 추가
flutter_launcher_icons:
android: true
ios: true
image_path: "assets/icon/icon.png"
min_sdk_android: 21
adaptive_icon_background: "#2196F3"
adaptive_icon_foreground: "assets/icon/icon.png"
아이콘 생성
flutter pub get flutter pub run flutter_launcher_icons
결과:
✓ Creating default icons Android
✓ Creating default icons iOS
✓ Creating adaptive icons Android
3️⃣ 앱 메타데이터 설정
AndroidManifest.xml 수정
위치:
android/app/src/main/AndroidManifest.xml
<manifest ...>
<application
android:label="LinkOn"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
변경사항:
android:label
: 앱 이름
build.gradle 수정
위치:
android/app/build.gradle
파일 확인
ls android/app/build.gradle*
주의:
.kts
파일이면 .gradle
로 변경 필요!# Kotlin DSL을 Groovy로 변경
mv android/app/build.gradle.kts android/app/build.gradle
build.gradle 설정
plugins {
id("com.android.application")
id("com.google.gms.google-services")
id("kotlin-android")
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "com.doythan.bookmarkmanager"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
applicationId = "com.doythan.bookmarkmanager" // ✅ 패키지명
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}
핵심 변경:
applicationId
:com.doythan.bookmarkmanager
로 변경
com.example
제거!
4️⃣ Keystore 생성 및 앱 서명
Keystore란?
앱 서명 키: Play Store에 업로드하는 모든 APK/AAB는 동일한 키로 서명되어야 함
중요:
- 키를 잃어버리면 앱 업데이트 영구 불가능!
- 반드시 안전한 곳에 백업!
Keystore 생성
keytool -genkey -v -keystore ~/upload-keystore.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias upload \
-storetype JKS
입력 프롬프트:
키 저장소 비밀번호를 입력하십시오: [강력한 비밀번호]
새 비밀번호를 다시 입력하십시오: [비밀번호 재입력]
이름과 성을 입력하십시오.
[알 수 없음]: 경원도
조직 단위 이름을 입력하십시오.
[알 수 없음]: 개인
조직 이름을 입력하십시오.
[알 수 없음]: Doythan
구/군/시 이름을 입력하십시오?
[알 수 없음]: Busan
시/도 이름을 입력하십시오.
[알 수 없음]: Busan
이 조직의 두 자리 국가 코드를 입력하십시오.
[알 수 없음]: KR
생성 확인:
ls -la ~/upload-keystore.jks
key.properties 파일 생성
위치:
android/key.properties
storePassword=[입력한 비밀번호]
keyPassword=[입력한 비밀번호]
keyAlias=upload
storeFile=/Users/dogyeong-won/upload-keystore.jks
⚠️ 보안 주의:
- 절대 Git에 커밋하지 말 것!
.gitignore
에 추가 필수!
.gitignore 업데이트
echo "android/key.properties" >> .gitignore
확인:
git status
# key.properties가 안 보여야 정상!
build.gradle에 서명 설정 추가
위치:
android/app/build.gradle
전체 파일:
plugins {
id("com.android.application")
id("com.google.gms.google-services")
id("kotlin-android")
id("dev.flutter.flutter-gradle-plugin")
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace = "com.doythan.bookmarkmanager"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
applicationId = "com.doythan.bookmarkmanager"
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig = signingConfigs.release
minifyEnabled true
shrinkResources true
}
}
}
flutter {
source = "../.."
}
추가된 부분:
def keystoreProperties
: key.properties 로드
signingConfigs
: 서명 설정
buildTypes.release
: Release 빌드 시 서명 적용
minifyEnabled
: 코드 난독화
shrinkResources
: 사용하지 않는 리소스 제거
5️⃣ Firebase 설정 업데이트
문제 상황
패키지명 변경 후 Firebase와 불일치:
Firebase: com.example.bookmark_manager
현재 앱: com.doythan.bookmarkmanager
에러:
No matching client found for package name 'com.doythan.bookmarkmanager'
해결: Firebase Console에서 Android 앱 추가
1. Firebase Console 접속
https://console.firebase.google.com/project/bookmark-manager-24e55/settings/general
2. Android 앱 추가
1. "앱 추가" 버튼 클릭
2. Android 아이콘 선택
3. Android 패키지 이름: com.doythan.bookmarkmanager
4. 앱 닉네임: LinkOn (선택)
5. 디버그 서명 인증서 SHA-1: (나중에 추가 가능)
6. "앱 등록" 클릭
3. google-services.json 다운로드
1. "google-services.json 다운로드" 버튼
2. 다운로드된 파일을 프로젝트에 복사
cp ~/Downloads/google-services.json android/app/
4. 확인
cat android/app/google-services.json | grep package_name
결과:
"package_name": "com.doythan.bookmarkmanager"
6️⃣ MainActivity 패키지 구조 정리
문제 발견
에러 상황: Debug 모드 실행 시 앱이 크래시
원인:
- 패키지 ID는
com.doythan.bookmarkmanager
로 변경
- 하지만 폴더 구조는 여전히
com.example.bookmark_manager
폴더 불일치:
현재: android/app/src/main/kotlin/com/example/bookmark_manager/
필요: android/app/src/main/kotlin/com/doythan/bookmarkmanager/
해결: 새 패키지 구조 생성
1. 새 폴더 생성
mkdir -p android/app/src/main/kotlin/com/doythan/bookmarkmanager
2. MainActivity.kt 생성
위치:
android/app/src/main/kotlin/com/doythan/bookmarkmanager/MainActivity.kt
package com.doythan.bookmarkmanager
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
3. 기존 폴더 삭제
rm -rf android/app/src/main/kotlin/com/example
최종 폴더 구조
android/app/src/main/kotlin/
└── com/
└── doythan/
└── bookmarkmanager/
└── MainActivity.kt
7️⃣ 빌드 및 테스트
Clean 빌드
flutter clean flutter pub get
Debug 빌드 테스트
flutter run
성공:
✓ Built build/app/outputs/flutter-apk/app-debug.apk
Installing build/app/outputs/flutter-apk/app-debug.apk...
Waiting for sdk gphone64 arm64 to report its views...
Debug service listening on ws://127.0.0.1:xxxxx
앱 실행 확인:
- ✅ 로그인 화면 표시
- ✅ 회원가입 가능
- ✅ 북마크 CRUD 동작
- ✅ 검색 동작
Release APK 빌드
flutter build apk --release
결과:
Font asset "CupertinoIcons.ttf" was tree-shaken,
reducing it from 257628 to 848 bytes (99.7% reduction).
Font asset "MaterialIcons-Regular.otf" was tree-shaken,
reducing it from 1645184 to 3508 bytes (99.8% reduction).
✓ Built build/app/outputs/flutter-apk/app-release.apk (50.1MB)
Tree-shaking:
- 사용하지 않는 아이콘 제거
- 99.7-99.8% 크기 감소!
Release AAB 빌드 (Play Store용)
flutter build appbundle --release
결과:
✓ Built build/app/outputs/bundle/release/app-release.aab (44.4MB)
APK vs AAB:
APK: 50.1MB (직접 설치용)
AAB: 44.4MB (Play Store 업로드용, 더 작음)
빌드 파일 확인
# APK
ls -lh build/app/outputs/flutter-apk/app-release.apk
# AAB
ls -lh build/app/outputs/bundle/release/app-release.aab
Release APK 에뮬레이터 테스트
# 기존 앱 삭제
adb uninstall com.doythan.bookmarkmanager
# Release APK 설치
adb install build/app/outputs/flutter-apk/app-release.apk
# 앱 실행
adb shell am start -n com.doythan.bookmarkmanager/.MainActivity
테스트 항목:
✅ 앱 아이콘 정상 표시
✅ 앱 이름 "LinkOn" 표시
✅ 모든 기능 정상 동작
✅ 성능 문제 없음
✅ 크래시 없음
8️⃣ 트러블슈팅
문제 1: Kotlin DSL vs Groovy 에러
에러:
Script compilation errors:
Line 01: def keystoreProperties = new Properties()
^ Unresolved reference: def
원인:
- 파일명이
build.gradle.kts
(Kotlin DSL)
- 하지만 코드는 Groovy 문법
해결:
mv android/app/build.gradle.kts android/app/build.gradle
문제 2: plugins 블록 순서
에러:
only buildscript {}, pluginManagement {} and other plugins {}
script blocks are allowed before plugins {} blocks
원인:
plugins {}
블록이 파일 맨 위에 와야 함해결:
plugins {}
블록을 파일 최상단으로 이동올바른 순서:
plugins {
// ...
}
def keystoreProperties = new Properties()
// ...
android {
// ...
}
문제 3: Firebase 패키지명 불일치
에러:
No matching client found for package name 'com.doythan.bookmarkmanager'
원인: Firebase에 새 패키지명 미등록
해결:
- Firebase Console에서 Android 앱 추가
- 패키지명:
com.doythan.bookmarkmanager
google-services.json
다운로드 및 교체
문제 4: MainActivity 패키지 구조 불일치
증상: Debug 모드 실행 시 "LinkOn keeps stopping"
원인:
- Application ID 변경
- 하지만 폴더 구조는 이전 패키지명
해결:
# 새 구조 생성
mkdir -p android/app/src/main/kotlin/com/doythan/bookmarkmanager
# MainActivity.kt 생성 (새 패키지명으로)
# 기존 폴더 삭제
rm -rf android/app/src/main/kotlin/com/example
문제 5: 에뮬레이터 저장 공간 부족
에러:
INSTALL_FAILED_INSUFFICIENT_STORAGE
해결:
Android Studio → Device Manager
→ 에뮬레이터 우측 ⋮ → Wipe Data
9️⃣ 빌드 최적화
Tree-shaking 효과
빌드 로그:
CupertinoIcons.ttf: 257KB → 848B (99.7% 감소)
MaterialIcons-Regular.otf: 1.6MB → 3.5KB (99.8% 감소)
사용하지 않는 아이콘 자동 제거!
난독화 및 리소스 축소
build.gradle:
buildTypes {
release {
minifyEnabled true // 코드 난독화
shrinkResources true // 리소스 축소
}
}
효과:
- 앱 크기 감소
- 역공학 방지
- 보안 향상
🔟 보안 체크리스트
Git 커밋 전 확인
# key.properties가 추적되지 않는지 확인
git status
# .gitignore 확인
cat .gitignore | grep key.properties
민감한 파일 목록
❌ 절대 커밋하면 안 됨:
- android/key.properties
- ~/upload-keystore.jks
- *.jks
- *.keystore
✅ 커밋해도 됨:
- android/app/google-services.json (클라이언트 설정)
- android/app/build.gradle
- lib/firebase_options.dart
Keystore 백업
# 안전한 곳에 백업 (필수!)
cp ~/upload-keystore.jks ~/Dropbox/backup/
# 또는 iCloud, Google Drive 등
중요:
- Keystore를 잃어버리면 앱 업데이트 영구 불가능!
- 비밀번호도 함께 기록!
1️⃣1️⃣ 최종 확인
빌드 파일 확인
# APK 확인
ls -lh build/app/outputs/flutter-apk/app-release.apk
# -rw-r--r-- 50.1MB
# AAB 확인
ls -lh build/app/outputs/bundle/release/app-release.aab
# -rw-r--r-- 44.4MB
# Keystore 확인
ls -la ~/upload-keystore.jks
서명 검증
jarsigner -verify -verbose -certs build/app/outputs/flutter-apk/app-release.apk
예상 결과 (마지막 줄):
jar verified.
패키지 정보 확인
~/Library/Android/sdk/build-tools/*/aapt dump badging build/app/outputs/flutter-apk/app-release.apk | grep package
결과:
package: name='com.doythan.bookmarkmanager' versionCode='1' versionName='1.0.0'
🎉 완료!
달성한 것들
✅ 앱 아이콘 설정
✅ 앱 이름 설정 (LinkOn)
✅ Application ID 변경
✅ 패키지 구조 정리
✅ Keystore 생성 및 백업
✅ 앱 서명 설정
✅ Firebase 설정 업데이트
✅ Debug 빌드 성공
✅ Release APK 빌드 (50.1MB)
✅ Release AAB 빌드 (44.4MB)
✅ 에뮬레이터 테스트 완료
✅ 트러블슈팅 완료
준비된 파일
📦 build/app/outputs/flutter-apk/app-release.apk (50.1MB)
→ 테스트용, 직접 설치 가능
📦 build/app/outputs/bundle/release/app-release.aab (44.4MB)
→ Play Store 업로드용
🔑 ~/upload-keystore.jks
→ 앱 서명 키 (백업 필수!)
⚙️ android/key.properties
→ 서명 설정 (Git 제외)
🚀 다음 단계 (#7 예고)
Google Play Console 등록 및 출시
필요한 것:
💰 Google Play Console 계정 ($25, 평생)
📸 스크린샷 4-8장
📝 앱 설명 작성
🎨 Feature Graphic (선택)
📋 개인정보처리방침 URL
진행 순서:
1. Play Console 계정 등록
2. 스크린샷 캡처
3. 앱 설명 작성
4. AAB 업로드
5. 내부 테스트
6. 프로덕션 출시
7. 심사 대기 (1-3일)
8. 출시 완료! 🎉
💡 배운 점
기술적 학습
Android 빌드:
- Keystore 생성 및 관리
- Gradle 설정 (Groovy vs Kotlin DSL)
- 앱 서명 프로세스
- Tree-shaking 최적화
패키지 관리:
- Application ID 변경 프로세스
- 패키지 구조와 폴더 구조 일치
- Firebase 설정 동기화
보안:
- 민감한 파일 관리
- .gitignore 설정
- Keystore 백업 중요성
트러블슈팅 경험
실전에서 겪은 문제들:
- Kotlin DSL vs Groovy 혼용
- plugins 블록 순서 문제
- Firebase 패키지명 불일치
- MainActivity 패키지 구조 불일치
- 에뮬레이터 저장 공간 부족
모든 문제를 해결하며 성장! 💪
📊 프로젝트 현황
완료된 플랫폼
✅ Web: https://bookmark-manager-24e55.web.app
🚧 Android: 빌드 완료, Play Store 등록 대기
📋 iOS: 계획 단계
기술 스택
Framework: Flutter 3.35.4
Language: Dart 3.9.2
Backend: Firebase (Auth, Firestore, Hosting)
State Management: Riverpod 3.0.3
Routing: go_router 16.2.4
Platform: Android, Web (iOS 예정)
📚 참고 자료
공식 문서
유용한 링크
🎓 학습 정리
이번 글에서 배운 것
빌드 프로세스:
- ✅ Android 앱 빌드 설정
- ✅ Keystore 생성 및 서명
- ✅ Release 빌드 프로세스
- ✅ APK vs AAB 차이
트러블슈팅:
- ✅ Gradle 설정 문제 해결
- ✅ Firebase 패키지명 동기화
- ✅ 패키지 구조 정리
- ✅ 실전 디버깅 경험
보안:
- ✅ 민감한 정보 관리
- ✅ Git 보안 설정
- ✅ Keystore 백업
🙏 마치며
Android 앱 빌드 준비가 완료되었습니다!
많은 시행착오가 있었지만, 모든 문제를 하나씩 해결하며 실전 경험을 쌓을 수 있었습니다.
Share article