DEV Community

Cover image for 🚀 Master Flutter CI/CD: Automate App Deployment with GitHub Actions
Sohanuzzaman Soad
Sohanuzzaman Soad

Posted on

🚀 Master Flutter CI/CD: Automate App Deployment with GitHub Actions

Are you tired of manually deploying your Flutter apps every time you make a change? It’s time to level up your CI/CD game with GitHub Actions! 💡

GitHub Actions offers a seamless way to automate your Flutter app’s build, test, and deployment processes for both Android and iOS, saving you time and effort. With just a few lines of YAML, you can create workflows that:

✅ Automatically build your Flutter app when you push to a specific branch.
✅ Run tests to ensure your app remains rock solid.
✅ Deploy APKs to Google Play Store or TestFlight for iOS with minimal manual intervention.

Why Automate Deployment?

Manual deployment is prone to errors, repetitive, and time-consuming. Automation ensures:

  • Consistency: Every build follows the same steps, leaving no room for missed configurations.
  • Speed: Focus on coding while GitHub Actions handles deployment.
  • Confidence: Continuous testing ensures every release is bug-free.

Setting Up GitHub Actions for Flutter

Here’s a step-by-step guide to setting up GitHub Actions for your Flutter app:

1. Create a Workflow File

Navigate to your project repository and create the directory .github/workflows/. Inside this directory, create a file named deploy.yml. This file will define the steps for automating your app deployment.

2. Define Workflow Triggers

Specify when the workflow should run, for example, on a push to the main branch:

on:
  push:
    branches:
      - main
Enter fullscreen mode Exit fullscreen mode

This ensures the workflow runs whenever new changes are pushed to the main branch.

3. Setup Flutter Environment

Install and configure Flutter in your workflow using the subosito/flutter-action:

- name: Setup Flutter
  uses: subosito/flutter-action@v2
  with:
    flutter-version: 'stable'
Enter fullscreen mode Exit fullscreen mode

4. Install Dependencies
Ensure all required packages are fetched:

- name: Install Dependencies
  run: flutter pub get

Enter fullscreen mode Exit fullscreen mode

5. Run Tests
Add a step to execute tests and validate the app:

- name: Run Tests
  run: flutter test
Enter fullscreen mode Exit fullscreen mode

6. Build the App
Build the APK (For Android):

- name: Build APK
  run: flutter build apk
Enter fullscreen mode Exit fullscreen mode

But in most cases we need Signed APK.
For Signed APK:

- name: Decode Keystore File
  run: echo "${{ secrets.ANDROID_KEYSTORE }}" | base64 --decode > android/app/keystore.jks

- name: Decode Keystore Credentials
  run: |
    echo "${{ secrets.KEYSTORE_ALIAS }}" | base64 --decode > keystore_alias.txt
    echo "${{ secrets.KEYSTORE_PASSWORD }}" | base64 --decode > keystore_password.txt
    echo "${{ secrets.KEY_PASSWORD }}" | base64 --decode > key_password.txt

- name: Build Signed APK
  run: |
    flutter build apk --release \
      --dart-define=KEYSTORE_PATH=android/app/keystore.jks \
      --dart-define=KEYSTORE_ALIAS=$(cat keystore_alias.txt) \
      --dart-define=KEYSTORE_PASSWORD=$(cat keystore_password.txt) \
      --dart-define=KEY_PASSWORD=$(cat key_password.txt)
Enter fullscreen mode Exit fullscreen mode

For iOS apps:

- name: Build iOS
  run: flutter build ios --no-codesign
Enter fullscreen mode Exit fullscreen mode

7. Deploy Automatically
Use deployment tools or scripts to upload your build to the respective platforms. Here’s an example for deploying to Google Play:

- name: Deploy to Google Play
  uses: r0adkll/upload-google-play@v1
  with:
    serviceAccountJson: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT }}
    packageName: com.example.yourapp
    releaseFiles: build/app/outputs/flutter-apk/app-release.apk
Enter fullscreen mode Exit fullscreen mode

For iOS, you can use fastlane or similar tools to deploy to TestFlight. I'll write another post about iOS deployments in depth.

Full Sample Workflow

Here’s a complete workflow example for Flutter deployment with a signed APK and Base64-encoded secrets:

name: Flutter Deployment

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout Repository
      uses: actions/checkout@v3

    - name: Setup Flutter
      uses: subosito/flutter-action@v2
      with:
        flutter-version: 'stable'

    - name: Install Dependencies
      run: flutter pub get

    - name: Run Tests
      run: flutter test

    - name: Decode Keystore File
      run: echo "${{ secrets.ANDROID_KEYSTORE }}" | base64 --decode > android/app/keystore.jks

    - name: Decode Keystore Credentials
      run: |
        echo "${{ secrets.KEYSTORE_ALIAS }}" | base64 --decode > keystore_alias.txt
        echo "${{ secrets.KEYSTORE_PASSWORD }}" | base64 --decode > keystore_password.txt
        echo "${{ secrets.KEY_PASSWORD }}" | base64 --decode > key_password.txt

    - name: Build Signed APK
      run: |
        flutter build apk --release \
          --dart-define=KEYSTORE_PATH=android/app/keystore.jks \
          --dart-define=KEYSTORE_ALIAS=$(cat keystore_alias.txt) \
          --dart-define=KEYSTORE_PASSWORD=$(cat keystore_password.txt) \
          --dart-define=KEY_PASSWORD=$(cat key_password.txt)

    - name: Deploy to Google Play
      uses: r0adkll/upload-google-play@v1
      with:
        serviceAccountJson: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT }}
        packageName: com.example.yourapp
        releaseFiles: build/app/outputs/flutter-apk/app-release.apk
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

By automating Flutter app deployment with GitHub Actions, ensuring signed APKs, and securely storing secrets in Base64, you save valuable time and minimize errors. A solid CI/CD pipeline ensures every release is reliable and reaches your users faster. 🌟

What challenges have you faced while setting up GitHub Actions? Let us know in the comments below! 💬

Top comments (0)