Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Microsoft adds Copilot-powered debugging features for .NET in Visual Studio

      August 21, 2025

      Blackstone portfolio company R Systems Acquires Novigo Solutions, Strengthening its Product Engineering and Full-Stack Agentic-AI Capabilities

      August 21, 2025

      HoundDog.ai Launches Industry’s First Privacy-by-Design Code Scanner for AI Applications

      August 21, 2025

      The Double-Edged Sustainability Sword Of AI In Web Design

      August 20, 2025

      How VPNs are helping people evade increased censorship – and much more

      August 22, 2025

      Google’s AI Mode can now find restaurant reservations for you – how it works

      August 22, 2025

      Best early Labor Day TV deals 2025: Save up to 50% on Samsung, LG, and more

      August 22, 2025

      Claude wins high praise from a Supreme Court justice – is AI’s legal losing streak over?

      August 22, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Preserving Data Integrity with Laravel Soft Deletes for Recovery and Compliance

      August 22, 2025
      Recent

      Preserving Data Integrity with Laravel Soft Deletes for Recovery and Compliance

      August 22, 2025

      Quickly Generate Forms based on your Eloquent Models with Laravel Formello

      August 22, 2025

      Pest 4 is Released

      August 22, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      FOSS Weekly #25.34: Mint 22.2 Features, FreeVPN Fiasco, Windows Update Killing SSDs, AI in LibreOffice and More

      August 21, 2025
      Recent

      FOSS Weekly #25.34: Mint 22.2 Features, FreeVPN Fiasco, Windows Update Killing SSDs, AI in LibreOffice and More

      August 21, 2025

      You’ll need standalone Word, PowerPoint, Excel on iOS, as Microsoft 365 app becomes a Copilot wrapper

      August 21, 2025

      Microsoft to Move Copilot Previews to iOS While Editing Returns to Office Apps

      August 21, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to Automate Flutter Testing and Builds with GitHub Actions for Android and iOS

    How to Automate Flutter Testing and Builds with GitHub Actions for Android and iOS

    August 22, 2025

    GitHub Actions is a CI/CD (Continuous Integration and Continuous Deployment) tool built directly into GitHub. It allows developers to define workflows, which are sequences of automated steps triggered by events such as pushing code, opening pull requests, or creating releases.

    For Flutter developers, GitHub Actions is a powerful way to automate testing, builds, and deployment across multiple platforms.

    This guide will walk you through setting up GitHub Actions for a Flutter project, covering everything from prerequisites to detailed explanations of the workflow.

    Table of Contents

    1. Why Use GitHub Actions in Flutter Development?

    2. Prerequisites

    3. Step 1: Create a New Flutter Project

    4. Step 2: Push the Project to GitHub

    5. Step 3: Create a GitHub Actions Workflow

      • Triggers

      • Jobs

    6. Step 4: Generate and Add a GitHub Token

    7. Step 5: Understanding the Workflow

      • Flutter Test Job

      • iOS App Build Job

      • Android APK Build Job

    8. Step 6: Push and Enable the Workflow

    9. Final Notes

    Why Use GitHub Actions in Flutter Development?

    GitHub Actions automated testing ensures that all code changes are validated with unit and integration tests. Continuous integration builds Flutter apps automatically to confirm that new code integrates correctly.

    Code analysis and linting can run automatically to enforce style and maintain code quality. Automated releases streamline the process of packaging and distributing apps. Custom workflows can be tailored to fit project-specific needs. Collaboration is also improved because developers can see workflow results directly in pull requests.

    By introducing GitHub Actions, Flutter projects become more reliable, maintainable, and efficient.

    Prerequisites

    Before setting up GitHub Actions for your Flutter project, make sure you have:

    1. Flutter SDK installed locally so you can create and test the project before pushing to GitHub.

    2. Git installed to manage version control and push your project to GitHub.

    3. A GitHub account and a new repository created for your Flutter project.

    4. Basic understanding of YAML syntax, since workflows are defined in .yml files.

    5. A GitHub personal access token (PAT) for releasing builds, which will be stored as a repository secret.

    Step 1: Create a New Flutter Project

    Start by creating a new Flutter project and navigating into it:

    flutter create gh_flutter
    cd gh_flutter
    

    Replace gh_flutter with your preferred project name. This initializes a Flutter project with the default structure and dependencies.

    Step 2: Push the Project to GitHub

    Initialize Git inside your project and push it to GitHub:

    git init
    git add .
    git commit -m "Initial commit"
    git remote add origin <repository_url>
    git push -u origin main
    

    Replace <repository_url> with the repository URL you created on GitHub. This links your local Flutter project to GitHub, allowing GitHub Actions to run on your repository.

    Step 3: Create a GitHub Actions Workflow

    Inside your project, create a workflow configuration file. Workflows must be placed inside .github/workflows/. Create a file named ci.yml:

    name: CI
    
    on:
      push:
        branches:
          - main
      pull_request:
        branches:
          - main
    
    jobs:
      flutter_test:
        name: Run Flutter Test
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - uses: actions/setup-java@v3
            with:
              distribution: 'temurin'
              java-version: '17'
          - uses: subosito/flutter-action@v2
            with:
              channel: 'stable'
          - run: flutter pub get
          - run: flutter --version
          - run: flutter analyze
          - run: flutter test
    
      build_iOSApp:
        name: Build Flutter App (iOS)
        needs: [flutter_test]
        runs-on: macos-latest
        steps:
          - uses: actions/checkout@v3
          - uses: actions/setup-java@v3
            with:
              distribution: 'temurin'
              java-version: '17'
          - uses: subosito/flutter-action@v2
            with:
              flutter-version: '3.19.0'
              dart-verion: '3.3.4'
              channel: 'stable'
          - run: flutter pub get
          - run: flutter clean
          - run: |
              flutter build ios --no-codesign
              cd build/ios/iphoneos
              mkdir Payload
              cd Payload
              ln -s ../Runner.app
              cd ..
              zip -r app.ipa Payload
    
      build_androidApk:
        name: Build Flutter App (Android)
        needs: [flutter_test]
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - uses: actions/setup-java@v3
            with:
              distribution: 'temurin'
              java-version: '17'
          - uses: subosito/flutter-action@v2
            with:
              channel: 'stable'
          - run: flutter pub get
          - run: flutter clean
          - run: flutter build apk --debug
          - uses: ncipollo/release-action@v1
            with:
              artifacts: "build/app/outputs/apk/debug/*"
              tag: v1.0.${{ github.run_number}}
              token: ${{ secrets.TOKEN}}
    

    This workflow is named CI and is meant for Continuous Integration (running tests and building apps automatically whenever code is pushed or a pull request is created).

    Triggers

    In GitHub Actions, triggers define the events that cause a workflow to run. For this workflow, it runs automatically when certain events happen in the repository. Specifically, it listens to:

    1. push: Whenever new code is pushed to the main branch, the workflow will start.

    2. pull_request: Whenever a pull request is opened or updated that targets the main branch, the workflow will also start.

    This ensures that both direct updates to the main branch and contributions through pull requests are validated and tested.

    on:
      push:
        branches:
          - main
      pull_request:
        branches:
          - main
    

    This code runs the workflow when:

    • You push commits to the main branch.

    • A pull request is opened or updated targeting main.

    Jobs

    There are 3 jobs in the workflow:

    Job 1: flutter_test runs unit tests and analysis.

    jobs:
      flutter_test:
        runs-on: ubuntu-latest
    

    It uses Ubuntu as the runner.

    Here are the steps it follows:

    1. Checks out code:

       - uses: actions/checkout@v3
      

      Downloads your repo into the runner.

    2. Sets up Java (needed for Flutter Android builds):

       - uses: actions/setup-java@v3
         with:
           distribution: 'temurin'
           java-version: '17'
      
    3. Sets up Flutter SDK:

       - uses: subosito/flutter-action@v2
         with:
           channel: 'stable'
      

      This installs the Flutter stable channel.

    4. Runs commands:

      1. flutter pub get installs dependencies.

      2. flutter --version checks installed Flutter version.

      3. flutter analyze analyzes Dart code for errors.

      4. flutter test runs unit/widget tests.

    If this job fails, later jobs won’t run.

    Job 2: build_iOSApp builds an iOS .ipa file.

      build_iOSApp:
        needs: [flutter_test]
        runs-on: macos-latest
    
      steps:
      - uses: actions/checkout@v3
    
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.22.0'
    
      - name: Install CocoaPods dependencies
        run: |
          cd ios
          pod install
    
      - name: Build iOS App
        run: flutter build ipa --release --no-codesign
    

    This runs only after flutter_test succeeds and uses macOS runner (needed for iOS builds).

    After installing CocoaPods dependencies, the workflow executes flutter build ipa --release --no-codesign. This shell command tells Flutter to package your iOS app into an .ipa file inside the runner’s build directory. The --no-codesign flag allows building without signing credentials, which is convenient for CI pipelines.

    Here are the steps it follows:

    1. Checks out repo + sets up Java (same as before).

    2. Sets up Flutter but this time pins:

       flutter-version: '3.19.0'
       dart-verion: '3.3.4'   # typo: should be `dart-version`
       channel: 'stable'
      
    3. Runs build:

      1. flutter pub get fetches packages.

      2. flutter clean cleans old builds.

      3. flutter build ios --no-codesign builds iOS app without signing.

      4. After building:

        1. Goes into build/ios/iphoneos

        2. Creates a Payload folder (needed for IPA structure).

        3. Symlinks the generated Runner.app into Payload.

        4. Zips the folder to app.ipa.

    Result: An unsigned .ipa file.

    Job 3: build_androidApk builds a debug Android .apk and uploads it as a release artifact.

      build_androidApk:
        needs: [flutter_test]
        runs-on: ubuntu-latest
    
      steps:
      - uses: actions/checkout@v3
    
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.22.0'
    
      - name: Build Android APK
        run: flutter build apk --release
    

    This runs only after tests pass.

    For Android, after setting up the Flutter environment, the workflow calls flutter build apk --release. This command compiles and packages the Android app into an .apk file ready for distribution. The resulting file is placed inside the build/app/outputs/flutter-apk directory of the project.

    Here are the steps it follows:

    1. Checks out repo, sets up Java, and sets up Flutter.

    2. Runs:

      1. flutter pub get

      2. flutter clean

      3. flutter build apk --debug creates a debug APK.

    3. Uploads APK using ncipollo/release-action@v1:

       artifacts: "build/app/outputs/apk/debug/*"
       tag: v1.0.${{ github.run_number }}
       token: ${{ secrets.TOKEN }}
      
      1. Uploads all debug APKs as release artifacts.

      2. Tags release as v1.0.<run_number> (e.g., v1.0.5).

      3. Uses a GitHub Personal Access Token (TOKEN) stored in repo secrets.

    Step 4: Generate and Add a GitHub Token

    The Android build job releases APKs using the release-action. To authenticate, you must provide a GitHub personal access token. To do this, go to GitHub Settings → Developer settings → Personal access tokens.

    Generate a new token with repo permissions and copy the token immediately. Then go to your repository → Settings → Secrets → New repository secret. Add the token with the name TOKEN.

    Now the workflow can use ${{ secrets.TOKEN }} securely.

    Step 5: Understanding the Workflow

    This workflow is triggered when code is pushed to the main branch or when a pull request is opened against it. Let’s break it down:

    Flutter Test Job

    • Environment: Runs on ubuntu-latest.

    Steps:

    1. actions/checkout@v3 fetches the source code.

    2. actions/setup-java@v3 installs Java, required for some Flutter tools.

    3. subosito/flutter-action@v2 installs Flutter on the runner.

    4. flutter pub get installs dependencies.

    5. flutter analyze checks for code issues.

    6. flutter test runs test cases.

    This job ensures your code compiles, passes linting, and has no failing tests.

    iOS App Build Job

    • Environment: Runs on macos-latest because iOS builds require macOS.

    • Dependencies: This job runs only if flutter_test passes (needs: [flutter_test]).

    Steps: Similar setup as before, but after cleaning old builds with flutter clean, it runs flutter build ios --no-codesign to build an iOS app without requiring a signing certificate. The shell commands package the app into an .ipa file.

    Android APK Build Job

    • Environment: Runs on ubuntu-latest.

    • Dependencies: Also depends on flutter_test.

    Steps:

    1. Installs Flutter.

    2. Runs flutter clean and then builds the Android APK.

    3. Uses ncipollo/release-action@v1 to upload the APK as a GitHub release, tagged automatically with a version like v1.0.<run_number>.

    Step 6: Push and Enable the Workflow

    Save your file as .github/workflows/ci.yml and push the changes:

    git add .
    git commit -m "Add GitHub Actions workflow"
    git push
    

    When you push your changes to GitHub, the workflow file is picked up automatically. To confirm that it is running, open your repository on GitHub and click on the Actions tab at the top of the page. You will see a list of workflow runs, each tied to the commit message that triggered them.

    Click on the most recent run to expand the details. Inside, you’ll find separate jobs for Android and iOS builds. Each job will show its status in real time:

    1. A yellow dot with “In progress” indicates the job is still running.

    2. A green check mark with “Success” means the job finished successfully.

    3. A red cross with “Failed” means something went wrong.

    This way, you can immediately tell whether your Android and iOS builds passed or if one of them needs attention.

    Running for Flutter Test

    Building for iOS

    Building for Android

    Jobs completed

    Showcase 2 app releases on the right hand side with versions

    Detailed app release versioning showcase

    Final Notes

    With this setup, you now have:

    • Automated testing whenever you push or open a pull request.

    • Automatic iOS builds on macOS runners.

    • Automatic Android builds with APKs released to GitHub.

    This ensures that every change is tested and that builds are consistently generated without manual steps.

    For more details, see the official GitHub Actions documentation: https://docs.github.com/en/actions.

    Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleInvoke the Mapbox Geocoding API to Populate the Location Autocomplete Functionality
    Next Article Why It Took Us Seven Years to Find Product Market Fit

    Related Posts

    Development

    Preserving Data Integrity with Laravel Soft Deletes for Recovery and Compliance

    August 22, 2025
    Development

    Quickly Generate Forms based on your Eloquent Models with Laravel Formello

    August 22, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    CVE-2025-49187 – Apache HTTP Server Username Brute Forcing

    Common Vulnerabilities and Exposures (CVEs)

    Deep Reinforcement Learning in Natural Language Understanding

    Development

    Akamai meldt actief misbruik van lekken in GeoVision IoT-apparaten

    Security

    CVE-2025-31715 – Vowifi Command Injection Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Highlights

    Development

    How to Build a Sustainable Open Source Contribution Routine

    July 16, 2025

    Contributing to open source sounds fun until life gets in the way. You get busy,…

    Tech Layoffs in 2025 Begin: Google, Microsoft, Meta and Other Tech Giants Cut Jobs Due to AI Amid Restructuring

    April 17, 2025

    I switched to $379 Android phone from my Pixel 9 Pro while traveling – and didn’t regret it

    April 2, 2025

    CSS @media Rule Explained

    June 29, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.