✦ Selamat Idul Fitri 1447 H πŸŒ™ Taqabbalallahu minna wa minkum. Mohon maaf lahir dan batin. ✦
ALFAkwt

Menyiapkan CI/CD untuk Proyek Flutter dengan GitHub Actions: Dari Commit ke Play Store

Β· 0 komentar Β· Β± 5 menit baca Β· πŸ‘ 283 dilihat
Diagram CI/CD pipeline Flutter menggunakan GitHub Actions

Ada satu ritual yang dulu selalu saya lakukan setiap mau rilis versi baru aplikasi: buka laptop, pastikan environment benar, jalankan build, tunggu, sign APK manual, upload ke Play Console, isi release notes. Kalau ada yang salah, ulangi dari awal.

Proses itu memakan waktu 45–90 menit setiap rilis. Dan karena sering melelahkan, saya jadi menunda rilis β€” yang artinya bug fix yang sudah selesai dua minggu lalu baru sampai ke pengguna tiga minggu kemudian.

Sekarang, setiap kali saya push tag ke GitHub, pipeline otomatis menjalankan test, membangun APK yang sudah di-sign, dan mengupload ke Play Store internal track. Tanpa saya sentuh apapun. Artikel ini adalah panduan lengkap untuk setup yang sama.


Gambaran Besar Pipeline

Pipeline yang akan kita bangun punya dua workflow:

Workflow 1 β€” CI (setiap push dan pull request):

  • Checkout kode
  • Setup Flutter
  • Install dependencies
  • Run analyzer (dart analyze)
  • Run semua test

Workflow 2 β€” CD (hanya saat push tag):

  • Semua langkah CI
  • Build release APK dan App Bundle
  • Sign dengan keystore production
  • Upload ke Google Play internal track

Langkah 1: Simpan Secrets di GitHub

Sebelum menulis workflow, kita perlu menyiapkan secrets. Buka repository di GitHub β†’ Settings β†’ Secrets and variables β†’ Actions.

Tambahkan secrets berikut:

  • KEYSTORE_BASE64 β€” file keystore Anda, dikonversi ke base64
  • KEY_ALIAS β€” alias key di keystore
  • KEY_PASSWORD β€” password key
  • STORE_PASSWORD β€” password keystore
  • PLAY_STORE_JSON_KEY β€” service account JSON dari Google Play Console

Untuk mengkonversi keystore ke base64:

base64 -i keystore-produksi.jks | pbcopy  # macOS
base64 -w 0 keystore-produksi.jks         # Linux

Langkah 2: Workflow CI

Buat file .github/workflows/ci.yml:

name: CI

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.19.0'
channel: 'stable'
cache: true
- name: Install dependencies
run: flutter pub get
- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .
- name: Analyze
run: flutter analyze --no-fatal-infos
- name: Run tests
run: flutter test --coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: coverage/lcov.info

Parameter cache: true di flutter-action sangat penting β€” ia mengcache Flutter SDK dan pub cache antara run. Tanpa ini, setiap run mengunduh Flutter dari awal (Β±800 MB), yang bisa menambah 3–5 menit ke setiap run.


Langkah 3: Workflow CD

Buat file .github/workflows/cd.yml:

name: CD

on:
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.19.0'
channel: 'stable'
cache: true
- name: Install dependencies
run: flutter pub get
- name: Run tests
run: flutter test
- name: Setup keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> android/key.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
- name: Build App Bundle
run: |
flutter build appbundle --release
--obfuscate
--split-debug-info=build/debug-info
- name: Upload to Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_JSON_KEY }}
packageName: com.alfakwt.namaaplikasi
releaseFiles: build/app/outputs/bundle/release/*.aab
track: internal
status: completed
- name: Cleanup keystore
if: always()
run: |
rm -f android/app/keystore.jks
rm -f android/key.properties

Perhatikan langkah "Cleanup keystore" yang menggunakan if: always() β€” ini memastikan file keystore selalu dihapus dari runner, bahkan jika langkah sebelumnya gagal.


Langkah 4: Setup key.properties di build.gradle

Di android/app/build.gradle, tambahkan konfigurasi signing:

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
}
}
}

Dan pastikan key.properties ada di .gitignore β€” jangan pernah commit file ini ke repository.


Langkah 5: Service Account untuk Play Store

Ini adalah langkah yang paling sering membingungkan. Untuk upload otomatis ke Play Store, Anda butuh service account Google Cloud dengan izin yang tepat.

Langkah-langkahnya:

  1. Buka Google Play Console
  2. Setup β†’ API access β†’ Link ke Google Cloud project
  3. Di Google Cloud Console, buat service account baru
  4. Download file JSON credential-nya
  5. Kembali ke Play Console, grant izin ke service account tersebut (minimal "Release to internal testing")
  6. Simpan isi JSON tersebut sebagai secret PLAY_STORE_JSON_KEY

Memicu Release: Konvensi Tag

Workflow CD aktif ketika ada push tag yang dimulai dengan "v". Konvensi yang saya gunakan:

# Rilis production
git tag -a v1.2.0 -m "Release 1.2.0: fitur pencarian dan perbaikan crash"
git push origin v1.2.0
# Internal testing
git tag -a v1.2.0-beta.1 -m "Beta 1.2.0: uji fitur pencarian"
git push origin v1.2.0-beta.1

Anda bisa memodifikasi workflow untuk memilih track Play Store (internal, alpha, beta, production) berdasarkan apakah tag mengandung "beta" atau tidak.


Berapa Lama Pipeline Berjalan?

Dari pengalaman di proyek saya sendiri:

  • CI (test saja): 4–6 menit
  • CD lengkap (test + build + upload): 12–18 menit

Dengan caching yang tepat, angka ini relatif stabil dan tidak terlalu dipengaruhi ukuran proyek selama dependency tidak berubah banyak.


Kesimpulan

Setup CI/CD membutuhkan investasi waktu di depan β€” mungkin setengah hari untuk pertama kali. Tapi setelah berjalan, ia menghemat puluhan jam per tahun, mengurangi human error di proses rilis, dan yang paling penting: membuat rilis menjadi sesuatu yang tidak Anda tunda lagi.

Ketika rilis semudah push sebuah tag, Anda akan rilis lebih sering. Rilis lebih sering berarti iterasi lebih cepat. Dan iterasi lebih cepat berarti produk yang lebih baik.

Semua dimulai dari satu file YAML.


Komentar

Belum ada komentar. Jadilah yang pertama menulis.

Tulis Komentar

↑