Build & Release #

Build untuk release berbeda dari build untuk development. App harus ditandatangani secara digital (signed) agar bisa didistribusikan — Android menggunakan keystore, iOS menggunakan certificate dan provisioning profile. Proses ini rumit pertama kali, tapi setelah setup dilakukan dengan benar, build berikutnya tinggal satu perintah.

Versioning di pubspec.yaml #

# pubspec.yaml
name: toko_saya
version: 2.3.1+45
#        │   │ │
#        │   │ └── build number (versionCode Android, CFBundleVersion iOS)
#        │   └──── patch -- bug fix (tidak ada fitur baru, tidak breaking)
#        └──────── minor -- fitur baru (backward compatible)
# major -- breaking change atau redesign besar

# Aturan versioning semantik (SemVer):
# 1.0.0  → pertama kali release ke Play Store
# 1.0.1  → bug fix
# 1.1.0  → fitur baru
# 2.0.0  → perubahan besar / redesign

# Build number HARUS selalu naik untuk setiap upload ke store
# Play Store: versionCode harus unik dan naik
# App Store:  CFBundleVersion harus unik dan naik

Android — Signing dan Build #

Buat Keystore #

# Buat keystore (simpan di tempat aman, JANGAN di dalam project!)
keytool -genkey -v \
  -keystore ~/keystore/toko-saya-release.jks \
  -storetype JKS \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000 \
  -alias upload

# Kamu akan diminta:
# - Keystore password (simpan!)
# - Key password (simpan!)
# - Nama, organisasi, kota, negara

Konfigurasi Signing #

# android/key.properties -- JANGAN commit ke git!
storePassword=passwordKeystore
keyPassword=passwordKey
keyAlias=upload
storeFile=/Users/nama/keystore/toko-saya-release.jks
// android/app/build.gradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    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
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Build Android #

# App Bundle untuk Play Store (DIREKOMENDASIKAN)
flutter build appbundle --release \
  --dart-define-from-file=.dart_define/production.json

# Output: build/app/outputs/bundle/release/app-release.aab

# APK untuk distribusi langsung (tidak via Play Store)
flutter build apk --release \
  --split-per-abi \                  # pisah per CPU architecture
  --dart-define-from-file=.dart_define/production.json

# Output:
# build/app/outputs/flutter-apk/app-arm64-v8a-release.apk
# build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk

iOS — Signing dan Build #

Prerequisites #

Yang dibutuhkan di Apple Developer Portal:
  1. App ID / Bundle ID terdaftar
  2. Distribution Certificate (.p12) -- untuk sign app
  3. Provisioning Profile -- untuk distribusi ke App Store
     (atau Ad Hoc untuk distribusi terbatas)

Setup Xcode Signing #

Di Xcode:
  1. Buka ios/Runner.xcworkspace
  2. Pilih target "Runner"
  3. Tab "Signing & Capabilities"
  4. Pilih Team kamu
  5. Pilih Provisioning Profile yang sesuai
  6. Pastikan "Automatically manage signing" sesuai dengan alur kamu
     - Manual signing: lebih kontrol, lebih cocok untuk CI/CD
     - Automatic signing: lebih mudah untuk development lokal

Build iOS #

# Build tanpa upload (hasilkan .xcarchive dulu)
flutter build ios --release \
  --dart-define-from-file=.dart_define/production.json

# Kemudian archive di Xcode:
# Product → Archive → Distribute App → App Store Connect

# Atau build IPA langsung (butuh signing setup yang benar)
flutter build ipa --release \
  --dart-define-from-file=.dart_define/production.json \
  --export-options-plist=ios/ExportOptions.plist

# Output: build/ios/ipa/toko_saya.ipa
<!-- ios/ExportOptions.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
  <key>method</key>
  <string>app-store</string>
  <key>teamID</key>
  <string>TEAM_ID_KAMU</string>
  <key>uploadBitcode</key>
  <false/>
  <key>uploadSymbols</key>
  <true/>
</dict>
</plist>

Upload ke Play Store #

# Install bundletool untuk validasi AAB
# https://github.com/google/bundletool

# Validasi AAB sebelum upload
bundletool validate --bundle=app-release.aab

# Upload manual via Play Console:
# https://play.google.com/console
# App → Release → Internal Testing / Closed Testing / Open Testing / Production
# → Create new release → Upload AAB → Review → Publish

# Atau via Google Play API (untuk CI/CD)
# Gunakan tool seperti Fastlane supply atau GitHub Action

Play Store Release Tracks #

Internal Testing  → hanya 100 tester internal, langsung tersedia
                    Cocok untuk: testing setiap build
Closed Testing    → hingga 2000 tester via email
(Alpha/Beta)        Cocok untuk: QA dan early adopter
Open Testing      → semua pengguna bisa opt-in
(Beta)              Cocok untuk: beta publik
Production        → semua pengguna di negara yang dipilih
                    Gunakan staged rollout: 10% → 25% → 50% → 100%

Upload ke App Store #

# Via Xcode:
# Window → Organizer → Archives → Distribute App → App Store Connect

# Via Transporter (App Apple):
# Drag & drop file .ipa ke Transporter → Deliver

# Via altool (command line, deprecated -- gunakan notarytool)
xcrun altool --upload-app -f toko_saya.ipa \
  --type ios \
  --apiKey API_KEY \
  --apiIssuer ISSUER_ID

App Store Review Tips #

Untuk mempercepat review:
  ✓ Sertakan demo account di "Notes for Reviewer"
    Username: [email protected]
    Password: TestPass123!
  ✓ Jelaskan fitur yang membutuhkan permission khusus
  ✓ Sertakan video demo jika ada alur yang tidak jelas
  ✓ Pastikan semua screenshot sudah diperbarui
  ✓ Pastikan privacy policy URL valid dan bisa diakses

Yang menyebabkan rejection:
  ✗ Crash saat launch
  ✗ UI yang incomplete atau placeholder teks
  ✗ Permission yang tidak digunakan tapi diminta
  ✗ Tidak ada fungsi nyata (app demo kosong)
  ✗ Pelanggaran guideline (copy dari app lain, konten berbahaya)

Checklist Sebelum Upload ke Store #

KODE:
  □ flutter analyze -- tidak ada warning atau error
  □ flutter test -- semua test lulus
  □ Version dan build number sudah di-increment di pubspec.yaml
  □ CHANGELOG sudah diperbarui

BUILD:
  □ Build dijalankan dengan --release flag
  □ Signing menggunakan keystore/certificate yang tepat
  □ --dart-define menggunakan konfigurasi production
  □ App diuji di device fisik dengan build release

STORE LISTING:
  □ Screenshot semua ukuran yang diminta sudah diperbarui
  □ Deskripsi dan release notes sudah diperbarui
  □ Privacy policy masih valid
  □ Rating content sudah diset dengan benar

TESTING RELEASE BUILD:
  □ Login dan flow utama berfungsi
  □ Tidak ada crash saat launch
  □ Deep link berfungsi
  □ Notifikasi berfungsi
  □ Permission flow berfungsi

Ringkasan #

  • Versioning: major.minor.patch+buildNumber di pubspec.yaml. Build number harus selalu naik untuk setiap upload ke store — tidak bisa diulang.
  • Android signing: buat keystore dengan keytool, simpan di luar project, konfigurasi via key.properties yang masuk .gitignore. Gunakan App Bundle (.aab) untuk Play Store — lebih kecil dari APK.
  • iOS signing: butuh Apple Developer account, Distribution Certificate, dan Provisioning Profile. Build IPA menggunakan flutter build ipa dengan ExportOptions.plist.
  • Gunakan Play Store release tracks secara bertahap: Internal → Closed Testing → Open Testing → Production dengan staged rollout 10%→25%→50%→100%.
  • App Store Review: selalu sertakan demo account dan penjelasan permission di “Notes for Reviewer” — ini mengurangi kemungkinan rejection karena reviewer tidak bisa mengakses fitur.
  • Jalankan checklist lengkap sebelum setiap upload: analyze, test, version bump, screenshot, privacy policy, testing di device fisik dengan build release.

← Sebelumnya: Flavors & Environment   Berikutnya: CI/CD →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact