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+buildNumberdi 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 viakey.propertiesyang 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 ipadenganExportOptions.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.