Mobile Development

Mobile CI/CD Pipeline

TOKEN

Pipeline CI/CD mobile — Fastlane, GitHub Actions, TestFlight, Play Store, code signing, beta testing, dan staged rollout

📋 Daftar Isi
  1. Mengapa CI/CD
  2. Fastlane
  3. GitHub Actions
  4. Code Signing
  5. TestFlight & Play Store
  6. Beta Testing
  7. Team Notifications
  8. Tips Pipeline
  9. Quiz Pemahaman

1. Mengapa CI/CD untuk Mobile?

CI/CD (Continuous Integration / Continuous Delivery) mengotomatisasi proses build, test, dan deployment aplikasi mobile. Tanpa CI/CD, proses rilis manual memakan waktu berjam-jam dan rentan human error.

Pipeline CI/CD Mobile
📝
Code Push
Git commit
Pull Request
🔨
Build & Test
Compile, Lint
Unit & UI Tests
🚀
Deploy
TestFlight
Play Store
💡 Mulai dari yang Sederhana

Mulai dengan CI yang menjalankan lint dan unit test. Tambahkan deployment otomatis setelah pipeline stabil. Jangan langsung setup full pipeline.

2. Fastlane

Fastlane adalah tool open-source yang mengotomatisasi build, signing, dan deployment untuk iOS dan Android.

Bash — Instalasi Fastlane
# Install via RubyGems
gem install fastlane

# Atau via Homebrew (macOS)
brew install fastlane

# Inisialisasi di proyek
cd ios && fastlane init
cd android && fastlane init
Ruby — Fastfile iOS
# ios/fastlane/Fastfile
default_platform(:ios)

platform :ios do
  desc "Run tests"
  lane :test do
    run_tests(
      scheme: "MyApp",
      devices: ["iPhone 15"],
      code_coverage: true,
    )
  end

  desc "Build & upload to TestFlight"
  lane :beta do
    # Increment build number
    increment_build_number(
      build_number: latest_testflight_build_number + 1
    )

    # Build
    build_app(
      scheme: "MyApp",
      export_method: "app-store",
      clean: true,
    )

    # Upload to TestFlight
    upload_to_testflight(
      skip_waiting_for_build_processing: true,
    )

    # Notify team
    slack(
      message: "New iOS build uploaded to TestFlight!",
      channel: "#releases",
    )
  end

  desc "Upload to App Store"
  lane :release do
    build_app(scheme: "MyApp", export_method: "app-store")
    upload_to_app_store(
      skip_metadata: false,
      skip_screenshots: true,
      submit_for_review: true,
      automatic_release: true,
    )
  end
end
Ruby — Fastfile Android
# android/fastlane/Fastfile
default_platform(:android)

platform :android do
  desc "Run tests"
  lane :test do
    gradle(task: "test")
  end

  desc "Build & upload to Play Store (internal track)"
  lane :beta do
    gradle(
      task: "bundle",
      build_type: "Release",
    )

    upload_to_play_store(
      track: "internal",
      aab: "app/build/outputs/bundle/release/app-release.aab",
      skip_upload_metadata: true,
      skip_upload_screenshots: true,
    )

    slack(message: "New Android build uploaded to Play Store!")
  end

  desc "Promote internal to production"
  lane :release do
    upload_to_play_store(
      track: "internal",
      track_promote_to: "production",
      skip_upload_aab: true,
      skip_upload_metadata: false,
    )
  end
end

3. GitHub Actions

YAML — GitHub Actions CI
# .github/workflows/ci.yml
name: Mobile CI

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

jobs:
  flutter-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.24.0'
          cache: true

      - name: Install dependencies
        run: flutter pub get

      - name: Analyze code
        run: flutter analyze --fatal-infos

      - name: Run tests
        run: flutter test --coverage

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          file: coverage/lcov.info

  build-android:
    needs: flutter-test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'

      - name: Build APK
        run: flutter build apk --release

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: android-release
          path: build/app/outputs/flutter-apk/app-release.apk

  build-ios:
    needs: flutter-test
    runs-on: macos-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2

      - name: Build IPA
        run: flutter build ipa --release --no-codesign

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ios-release
          path: build/ios/ipa/*.ipa

4. Code Signing

YAML — Code Signing dengan Fastlane Match
# .github/workflows/release.yml
name: Release

on:
  push:
    tags: ['v*']

jobs:
  deploy-ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.2'
          bundler-cache: true

      - name: Install Fastlane
        run: bundle install

      - name: Setup signing
        env:
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
        run: |
          cd ios
          bundle exec fastlane match appstore --readonly

      - name: Build & Upload
        env:
          APP_STORE_CONNECT_API_KEY: ${{ secrets.ASC_API_KEY }}
        run: |
          cd ios
          bundle exec fastlane beta
⚠️ Jangan Commit Secrets

Gunakan GitHub Secrets untuk menyimpan API keys, passwords, dan certificates. JANGAN pernah commit credentials ke repository.

5. TestFlight & Play Store

PlatformTrackAudienceReview Time
TestFlight InternalInternal testingTim internal (100 orang)Tidak perlu review
TestFlight ExternalBeta testingPublik (10.000 orang)1-3 hari
Play Internalinternal100 testerTidak perlu review
Play Closedclosed (alpha/beta)UndanganBeberapa jam
Play Openopen (beta)Publik (link)Beberapa jam
Play ProductionproductionSemua user1-7 hari

6. Beta Testing Strategy

YAML — Automated Beta Deploy
# .github/workflows/beta.yml
name: Deploy Beta

on:
  workflow_dispatch:
    inputs:
      platform:
        description: 'Platform'
        required: true
        type: choice
        options: ['ios', 'android', 'both']
      track:
        description: 'Track'
        required: true
        type: choice
        options: ['internal', 'closed', 'open']

jobs:
  beta-android:
    if: inputs.platform == 'android' || inputs.platform == 'both'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'

      - run: flutter build appbundle --release

      - uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
          packageName: com.myapp
          releaseFiles: build/app/outputs/bundle/release/app-release.aab
          track: ${{ inputs.track }}

  beta-ios:
    if: inputs.platform == 'ios' || inputs.platform == 'both'
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - name: Deploy to TestFlight
        run: cd ios && bundle exec fastlane beta

6.1 Testing Ring Strategy

RingSiapaUkuranTujuan
Ring 0Developer1-5Smoke test
Ring 1QA Team5-20Regression test
Ring 2Internal team20-100Dogfooding
Ring 3Beta users100-1000Real-world testing
Ring 4ProductionSemuaFull release
YAML — Staged Rollout
# Android staged rollout
- uses: r0adkll/upload-google-play@v1
  with:
    serviceAccountJsonPlainText: ${{ secrets.PLAY_SA }}
    packageName: com.myapp
    releaseFiles: app-release.aab
    track: production
    # Rollout ke 20% user dulu
    status: inProgress
    userFraction: 0.2

# Setelah yakin stabil, promote ke 100%
# Bisa dilakukan manual di Play Console

7. Team Notifications

YAML — Slack & Email Notifications
# Tambahkan di akhir workflow
  notify:
    needs: [deploy-ios, deploy-android]
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Notify Slack
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "🚀 Release ${{ github.ref_name }} deployed!",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*Release ${{ github.ref_name }}*\nPlatform: ${{ github.event.inputs.platform }}\nTrack: ${{ github.event.inputs.track }}"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
📋 Post-Deploy Checklist

Setelah deploy: (1) Monitor crash reports 24 jam, (2) Cek analytics & user feedback, (3) Siapkan rollback plan, (4) Update release notes.

8. Tips Pipeline yang Efisien

TipsManfaat
Cache dependencies (pub, gradle, cocoapods)Build 2-5x lebih cepat
Run tests secara paralelKurangi total pipeline time
Conditional build (changed files only)Skip build jika tidak ada perubahan
Separate CI & CD pipelineCI di setiap push, CD manual/tag only
Artifact retention policyHapus build lama untuk hemat storage
Build matrix (debug + release)Test kedua variant sekaligus

Quiz Pemahaman

Pertanyaan 1: Tool apa yang mengotomatisasi build, signing, dan deployment mobile?

a) Gradle
b) CocoaPods
c) Fastlane
d) Xcode

Pertanyaan 2: Track apa di Play Store yang tidak memerlukan review?

a) production
b) open testing
c) closed testing
d) internal testing

Pertanyaan 3: Layanan Apple apa untuk beta distribution?

a) App Store Connect
b) TestFlight
c) Xcode Cloud
d) Apple Developer

Pertanyaan 4: Di mana menyimpan API keys di GitHub Actions?

a) Di file config
b) Di README
c) Di GitHub Secrets
d) Di .env file

Pertanyaan 5: Apa fungsi staged rollout di Play Store?

a) Build otomatis
b) Release bertahap ke persentase user tertentu
c) Rollback otomatis
d) A/B testing
← SebelumnyaKembali ke Beranda Selanjutnya →Lihat Kategori
🔍 Zoom
100%
🎨 Tema