inblog logo
|
Gyeongwon's blog
    PJT

    [Flutter + Firebase로 북마크 앱 만들기 #6] Android 앱 빌드 및 Play Store 배포 준비

    도경원's avatar
    도경원
    Oct 11, 2025
    [Flutter + Firebase로 북마크 앱 만들기 #6] Android 앱 빌드 및 Play Store 배포 준비
    Contents
    📌 시리즈 목차🎯 이번 글에서 다룬 내용📱 목표: Play Store 배포 준비 완료1️⃣ Android 빌드 준비2️⃣ 앱 아이콘 설정3️⃣ 앱 메타데이터 설정4️⃣ Keystore 생성 및 앱 서명5️⃣ Firebase 설정 업데이트6️⃣ MainActivity 패키지 구조 정리7️⃣ 빌드 및 테스트8️⃣ 트러블슈팅9️⃣ 빌드 최적화🔟 보안 체크리스트1️⃣1️⃣ 최종 확인🎉 완료!🚀 다음 단계 (#7 예고)💡 배운 점📊 프로젝트 현황📚 참고 자료🎓 학습 정리🙏 마치며

    📌 시리즈 목차

    • #1 프로젝트 초기 설정 및 Firebase 연동
    • #2 프로젝트 구조 설계 및 Riverpod 적용
    • #3 Firebase Authentication 연동 및 로그인 구현
    • #4 Firestore 연동 및 북마크 CRUD 구현
    • #5 Firebase Hosting으로 웹 배포하기
    • #6 Android 앱 빌드 및 Play Store 배포 준비 ← 현재 글
    • #7 스마트 URL 런처 구현 (SNS 앱 연동)
    • #8 스마트 카테고리 관리 시스템
    • #9 모던 UI 디자인 시스템 구축

    🎯 이번 글에서 다룬 내용

    • 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에 새 패키지명 미등록
    해결:
    1. Firebase Console에서 Android 앱 추가
    1. 패키지명: com.doythan.bookmarkmanager
    1. 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 백업 중요성

    트러블슈팅 경험

    실전에서 겪은 문제들:
    1. Kotlin DSL vs Groovy 혼용
    1. plugins 블록 순서 문제
    1. Firebase 패키지명 불일치
    1. MainActivity 패키지 구조 불일치
    1. 에뮬레이터 저장 공간 부족
    모든 문제를 해결하며 성장! 💪

    📊 프로젝트 현황

    완료된 플랫폼

    ✅ 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 예정)

    📚 참고 자료

    공식 문서

    • Flutter Android Build
    • Android App Signing
    • Firebase Android Setup

    유용한 링크

    • Google Play Console
    • Keystore 관리
    • APK vs AAB

    🎓 학습 정리

    이번 글에서 배운 것

    빌드 프로세스:
    • ✅ Android 앱 빌드 설정
    • ✅ Keystore 생성 및 서명
    • ✅ Release 빌드 프로세스
    • ✅ APK vs AAB 차이
    트러블슈팅:
    • ✅ Gradle 설정 문제 해결
    • ✅ Firebase 패키지명 동기화
    • ✅ 패키지 구조 정리
    • ✅ 실전 디버깅 경험
    보안:
    • ✅ 민감한 정보 관리
    • ✅ Git 보안 설정
    • ✅ Keystore 백업

    🙏 마치며

    Android 앱 빌드 준비가 완료되었습니다!
    많은 시행착오가 있었지만, 모든 문제를 하나씩 해결하며 실전 경험을 쌓을 수 있었습니다.
    Share article
    Contents
    📌 시리즈 목차🎯 이번 글에서 다룬 내용📱 목표: Play Store 배포 준비 완료1️⃣ Android 빌드 준비2️⃣ 앱 아이콘 설정3️⃣ 앱 메타데이터 설정4️⃣ Keystore 생성 및 앱 서명5️⃣ Firebase 설정 업데이트6️⃣ MainActivity 패키지 구조 정리7️⃣ 빌드 및 테스트8️⃣ 트러블슈팅9️⃣ 빌드 최적화🔟 보안 체크리스트1️⃣1️⃣ 최종 확인🎉 완료!🚀 다음 단계 (#7 예고)💡 배운 점📊 프로젝트 현황📚 참고 자료🎓 학습 정리🙏 마치며

    Gyeongwon's blog

    RSS·Powered by Inblog