Membuat CI/CD Pipeline untuk Aplikasi Flutter dengan GitHub Actions: Build, Test, dan Deploy ke Play Store

Lhuqita Fazry
Docker & DevOps Flutter GitHub Actions Fastlane CI/CD
Membuat CI/CD Pipeline untuk Aplikasi Flutter dengan GitHub Actions: Build, Test, dan Deploy ke Play Store

Deployment aplikasi Flutter secara manual memakan waktu dan rawan error. Kita harus menjalankan flutter build di mesin lokal, memastikan semua test sudah lewat, lalu mengupload file APK atau AAB ke Play Console secara berulang setiap kali ada rilis baru. Proses ini semakin berat ketika tim berkembang dan jumlah commit bertambah.

Bayangkan sebuah tim yang merilis versi baru setiap minggu. Setiap rilis, developer harus memastikan branch main bersih, menjalankan seluruh test di mesin masing-masing, lalu menunggu flutter build appbundle yang memakan waktu lama. Ketika rilis ditangani oleh orang berbeda, hasil build tidak selalu identik karena environment mesin lokal berbeda. Satu langkah terlewat seperti lupa menandatangani build baru baru disadari setelah artefak sampai ke Play Console, dan perbaikannya mengulang seluruh proses dari awal.

Belum lagi proses review dari tim QA yang sering menunggu artefak dikirim manual melalui chat atau email. Setiap revisi kecil memaksa build baru dan menunggu persetujuan berikutnya, sehingga komunikasi bolak-balik justru menghabiskan waktu yang seharusnya dipakai untuk mengembangkan fitur baru.

CI/CD pipeline menjawab tantangan tersebut dengan otomasi. Setiap perubahan kode yang masuk ke repository langsung di-build, di-test, dan disiapkan untuk rilis tanpa intervensi manual. Keuntungan utamanya adalah umpan balik yang cepat: jika ada error, developer mengetahuinya dalam hitungan menit, bukan saat aplikasi sudah sampai ke pengguna. Selain itu, setiap anggota tim memakai alur yang sama, sehingga tidak ada lagi proses rilis yang bergantung pada pengetahuan pribadi satu orang.

Pipeline yang akan kita bangun mengikuti alur trigger -> test -> build -> deploy. GitHub Actions mendeteksi perubahan kode, menjalankan test dan analisis statis, membangun Android App Bundle, lalu menguploadnya ke Play Store. Konsistensi juga terjaga karena setiap build berjalan di environment yang sama, sehingga artefak release selalu siap ketika dibutuhkan.

Gambar: Diagram alur Continuous Delivery (check in → build & unit test → acceptance test → release) - Sumber: [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Continuous_Delivery_process_diagram.svg)

Struktur Dasar Workflow GitHub Actions untuk Proyek Flutter

Workflow GitHub Actions didefinisikan dalam file YAML di direktori .github/workflows/. Komponen utamanya adalah on yang menentukan trigger, jobs yang berisi langkah eksekusi, runs-on yang memilih environment runner, dan steps yang dijalankan secara berurutan. Untuk proyek Flutter, kita memerlukan action subosito/flutter-action@v2 yang menginstall Flutter SDK beserta channel yang dipilih.

File pertama berikut menunjukkan workflow dasar: checkout repository, setup Flutter, dan install dependencies.

yamlyaml
name: Flutter CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  verify:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout kode
        uses: actions/checkout@v4

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: stable
          cache: true

      - name: Install dependencies
        run: flutter pub get

Blok on memastikan workflow berjalan saat ada push ke branch main dan setiap kali ada pull_request ke branch yang sama. Action subosito/flutter-action@v2 dengan parameter channel: stable menginstall Flutter SDK versi stabil. Parameter cache: true membuat action ini menyimpan cache berdasarkan pubspec.lock, sehingga flutter pub get tidak mengunduh ulang package yang sama di setiap run. Job verify berjalan di ubuntu-latest, sebuah environment Linux sementara yang disediakan GitHub.

Menjalankan Test Otomatis dengan Flutter Test dan Analisis Kode

Test adalah gerbang utama sebelum perubahan kode diterima. Setiap pull request harus lolos semua test sebelum di-merge, dan GitHub Actions menjadikan aturan ini mudah diterapkan lewat required status check. Kita menambahkan dua langkah kualitas: flutter analyze untuk mendeteksi masalah statis seperti error tipografi atau unused import, dan flutter test untuk menjalankan unit test serta widget test. Error kecil seperti typo pada nama variabel atau format kode yang tidak konsisten akan terdeteksi lebih awal, sehingga code review bisa fokus pada logika dan arsitektur daripada hal-hal mekanis.

Advanced Flutter State Management with BLoC
Mobile App • Intermediate

Advanced Flutter State Management with BLoC

Master advanced Flutter state management by building a production-ready applicat...

Daftar
yamlyaml
      - name: Analisis kode statis
        run: flutter analyze

      - name: Jalankan unit dan widget test
        run: flutter test --coverage

flutter analyze membaca seluruh kode dan melaporkan masalah yang berpotensi menjadi bug sebelum test dijalankan. Tool ini juga menangkap pemakaian API yang sudah deprecated serta pelanggaran lint rule yang didefinisikan di analysis_options.yaml, sehingga gaya kode tim tetap konsisten. flutter test --coverage mengeksekusi setiap test file dan menghasilkan laporan coverage di direktori coverage/. Widget test sangat penting bagi aplikasi mobile karena tool ini memverifikasi perilaku UI seperti ketukan tombol, pengisian form, dan navigasi antar halaman, yang tidak bisa dijamin oleh unit test biasa. Hasilnya tampil di halaman Actions sebagai daftar test per file dengan status pass atau fail. Jika ada satu test yang gagal, exit code dari perintah ini bernilai bukan nol, dan GitHub menghentikan workflow pada step tersebut. Developer langsung melihat test mana yang bermasalah beserta pesan assertion-nya, tanpa harus menjalankan ulang seluruh suite di mesin lokal. Kehadiran test yang lengkap juga menjadi dokumentasi hidup tentang bagaimana setiap fitur seharusnya berperilaku, sehingga developer baru bisa memahami ekspektasi aplikasi hanya dengan membaca kode test.

Build Android App Bundle dan Publikasi Artefak Release

Ada dua format build untuk distribusi Android: flutter build apk menghasilkan file APK untuk distribusi manual atau sideload, sedangkan flutter build appbundle menghasilkan file AAB yang dioptimalkan untuk upload ke Play Store. Play Store memakai AAB untuk menyusun APK yang disesuaikan dengan perangkat pengguna, sehingga ukuran unduhan lebih kecil.

Gambar: Struktur Android App Bundle (base module, feature modules, dan asset packs) - Sumber: [Android Developers](https://developer.android.com/guide/app-bundle/app-bundle-format)

Untuk menandatangani release build, kita memerlukan keystore dan file key.properties. Keduanya tidak boleh masuk ke repository. Pendekatan yang aman adalah menyimpan keystore dalam bentuk base64 di repository secret, lalu mendekode dan menulisnya di dalam workflow.

yamlyaml
      - name: Siapkan keystore dan key.properties
        run: |
          echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > keystore.jks
          echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > android/key.properties
          echo "keyPassword=${{ secrets.KEYSTORE_PASSWORD }}" >> android/key.properties
          echo "keyAlias=${{ secrets.KEYSTORE_ALIAS }}" >> android/key.properties
          echo "storeFile=../../keystore.jks" >> android/key.properties

      - name: Build appbundle release
        run: flutter build appbundle --release

      - name: Upload artifact AAB
        uses: actions/upload-artifact@v4
        with:
          name: app-release
          path: build/app/outputs/bundle/release/app-release.aab

File key.properties ditulis di dalam direktori android/ agar dibaca oleh konfigurasi signing di build.gradle. Nilai password dan alias diambil dari secrets, sehingga tidak pernah tertulis secara literal di repository. Setelah build selesai, action actions/upload-artifact@v4 menyimpan file app-release.aab sebagai artifact di halaman workflow. Tim QA dapat mengunduhnya untuk pengujian manual tanpa perlu build ulang.

Mengintegrasikan Fastlane untuk Upload Otomatis ke Play Store

Upload ke Play Store masih bisa dilakukan manual melalui Play Console, tetapi cara ini tidak scalable ketika rilis dilakukan rutin. Fastlane menyelesaikan masalah tersebut: otomatisasi penuh, manajemen release notes, dan autentikasi lewat service account tanpa perlu login browser.

Fastlane dikonfigurasi melalui file Fastfile berbahasa Ruby. Kita perlu menginstall Fastlane di runner terlebih dahulu, lalu mendefinisikan lane deploy. Cara paling sederhana adalah gem install fastlane, tetapi untuk memastikan versi yang sama dipakai di semua environment, pendekatan yang lebih disarankan adalah mencantumkan gem fastlane di dalam Gemfile dan menjalankan bundle install. Dengan begitu mesin lokal dan runner CI selalu sinkron, sehingga perilaku pipeline tidak berubah karena perbedaan versi gem. Sebelum Fastlane bisa mengakses Play Store, kita perlu membuat service account dari Google Cloud Console dan mengaktifkan Google Play Developer API untuk project tersebut. Account yang dibuat kemudian didaftarkan di Play Console dengan permission Release, dan file JSON yang diunduh dari Google Cloud menjadi kredensial yang dipakai sebagai json_key_file.

rubyruby
platform :android do
  desc "Build appbundle dan upload ke track internal"
  lane :deploy do
    sh "flutter build appbundle --release"
    upload_to_play_store(
      track: "internal",
      aab: "build/app/outputs/bundle/release/app-release.aab",
      json_key_file: "service_account.json",
      release_status: "completed"
    )
  end
end

Lane deploy menjalankan build appbundle melalui perintah sh, lalu memanggil action upload_to_play_store. Parameter track: "internal" menentukan bahwa build dikirim ke track internal testing, bukan langsung ke production. Track ini cocok untuk pengujian awal oleh tim internal, dan build yang sudah terbukti stabil bisa dipromosikan ke track beta atau production dari halaman Play Console tanpa perlu build ulang. Autentikasi dilakukan dengan service_account.json, file JSON dari Google Cloud yang memiliki akses ke Play Console dengan permission Release. Parameter json_key_file menunjuk ke lokasi file kredensial tersebut, dan Fastlane menggunakannya untuk meminta token akses ke Google Play API secara otomatis tanpa login manual. File ini disimpan sebagai secret dan didecode di workflow, sehingga kredensial Play Console tidak pernah terekspos. Setelah eksekusi, log Fastlane menampilkan versi build yang berhasil diupload beserta nomor versi dan link menuju release di Play Console. Di dalam workflow, lane ini dijalankan melalui step bundle exec fastlane deploy yang ditempatkan setelah proses build appbundle selesai, sehingga seluruh rangkaian upload berjalan tanpa intervensi manual.

Best Practices untuk Workflow yang Stabil dan Aman

Workflow yang stabil dimulai dari manajemen secret yang disiplin. Keystore password, API key, dan service_account.json hanya boleh berada di repository secrets, bukan ditulis langsung di file workflow. GitHub memastikan nilai secret tidak pernah muncul di log, dan aksesnya dapat dicabut kapan saja.

Branch protection adalah lapisan keamanan kedua. Aktifkan required status check pada branch main, lalu pilih job verify sebagai syarat merge. Pull request yang gagal test tidak bisa di-merge, sehingga kode berkualitas rendah tidak pernah masuk ke branch utama.

Otomatiskan juga nomor versi build agar tidak terjadi tabrakan versionCode di Play Store. Setiap upload menuntut versionCode yang lebih besar dari sebelumnya, dan mengelolanya manual sangat rawan kelupaan. Kita bisa memanfaatkan github.run_number dari GitHub Actions sebagai sumber nilai tersebut dan meneruskannya ke build.gradle, sehingga setiap run pipeline menghasilkan build yang unik tanpa mengedit file secara manual.

Manfaatkan juga caching agar setiap run lebih cepat. Selain cache: true pada subosito/flutter-action, pastikan flutter pub get jarang mengunduh ulang dengan menyimpan direktori ~/.pub-cache ke dalam cache GitHub Actions. Pipeline yang berjalan setiap hari akan menghemat banyak waktu dari hal kecil seperti ini, dan hasilnya terasa ketika build mulai sering dijalankan.

Terakhir, tambahkan notifikasi kegagalan. GitHub mengirim email secara default, tetapi integrasi Slack atau Discord memberi visibilitas lebih baik bagi tim. Pantau juga durasi workflow secara berkala; jika build mulai melambat, evaluasi kembali strategi caching dan kebutuhan dependency. Pipeline yang cepat dan dapat diandalkan akan membuat tim lebih produktif tanpa rasa khawatir saat merilis versi baru.

Mau membangun pipeline CI/CD yang solid untuk proyek Flutter atau menguasai DevOps secara sistematis? Bergabunglah dengan kursus dan bootcamp di Rumah Coding. Kurikulum praktis dengan proyek real-world dan mentorship dari praktisi industri akan membantumu menerapkan otomasi ini langsung di proyek nyata.

Kursus Terkait

TaskSync: Real-Time Collaborative Task Manager
Kursus Premium Mobile App

Advanced Flutter State Management with BLoC

Master advanced Flutter state management by building a production-ready application. This intermediate course uses a top-down, problem-driven approach, plunging you into real-world engineering challenges. You will learn to architect scalable applications, handle complex reactive states, manage multi-BLoC communication, synchronize real-time data, and implement optimistic UI updates using industry-standard BLoC patterns.

Proyek Akhir

TaskSync: Real-Time Collaborative Task Manager

  • Role-Based Authentication: Secure login and session management, dynamically reflecting user states across the entire application.
  • Real-Time Task Board: A Kanban-style board that instantly updates across all devices when any team member creates, moves, or deletes a task.
  • Advanced Search & Filtering: High-performance local search with event debouncing to prevent unnecessary API calls.
7 Weeks Intermediate
Lihat Detail Kursus
DailyQuest: Gamified Habit Tracker
Kursus Premium Mobile App

Flutter Mobile Development

Launch your mobile development journey with this immersive, project-based Flutter course. Designed specifically for beginners, this program takes you from coding fundamentals in Dart to deploying a fully functional mobile app. You will learn to craft beautiful, responsive UIs, handle global state management, and integrate cloud backends. By the end of the course, you will have built a real-world, cloud-synced application from scratch.

Proyek Akhir

DailyQuest: Gamified Habit Tracker

  • Secure Authentication: User registration and login functionality using email and password.
  • Cloud Data Synchronization: Real-time database integration (using Supabase or Firebase) to securely store and retrieve user habits.
  • Full CRUD Operations: The ability for users to Create, Read, Update, and Delete their daily tasks and habits.
7 Weeks Beginner
Lihat Detail Kursus

Artikel Terkait