# Implementing CI/CD for Flutter apps Using GitHub Actions

Continuous Integration and Continuous Deployment (CI/CD) is a crucial part of the software development process. It helps automate the build, testing, and deployment of your application, ensuring that code changes are integrated and deployed smoothly. In this blog post, I'll walk you through setting up CI/CD for a Flutter application using GitHub Actions.

### Prerequisites

Before you start, ensure that you have the following prerequisites in place:

1. A Flutter project hosted on GitHub.
    
2. Flutter installed on your development machine.
    
3. A basic understanding of GitHub Actions.
    

### GitHub Actions Workflow

GitHub Actions uses YAML files to define workflows. In this example, we've defined a workflow named "Build & Release" that runs when pull requests are created or pushed to the `main`, `master`, or `develop` branches.

```yaml
on:
  pull_request:
    branches:
      - main
      - master
  push:
    branches:
      - main
      - master
      - develop
name: "Build & Release"
```

This workflow is triggered both on pull requests and direct pushes to specific branches.

### Workflow Steps

A sample of the workflow is shown below which basically performs all the continuous integration(CI) part.

```yaml
on:
  pull_request:
    branches:
      - main
      - master
  push:
    branches:
      - main
      - master
      - develop
name: "Build & Release"
jobs:
  build:
    name: Build & Release
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-java@v1
        with:
          java-version: '12.x'
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: '3.13.9'
      - run: flutter pub get
      - run: flutter test
      - run: flutter build apk --debug --split-per-abi
      - run: |
          flutter build ios --no-codesign
          cd build/ios/iphoneos
          mkdir Payload
          cd Payload
          ln -s ../Runner.app
          cd ..
          zip -r app.ipa Payload
      - name: Push to Releases
        uses: ncipollo/release-action@v1
        with:
          artifacts: "build/app/outputs/apk/debug/*,build/ios/iphoneos/app.ipa"
          tag: v1.0.${{ github.run_number }}
          token: ${{ secrets.TOKEN }}
```

Let's break down the individual steps in our CI/CD workflow:

1. Check Out the Code
    
    The `actions/checkout` action is used to clone your repository into the runner's workspace.
    
    ```yaml
    jobs:
      build:
        steps:
          - uses: actions/checkout@v1
    ```
    
2. Set up Java
    
    ```yaml
          - uses: actions/setup-java@v1
            with:
              java-version: '12.x'
    ```
    
3. Set up Flutter
    
    Next, we use the `subosito/flutter-action` action to install the specified Flutter version.
    
    ```yaml
          - uses: subosito/flutter-action@v1
            with:
              flutter-version: '3.13.9'
    ```
    
4. Get Dependencies & Run Tests
    
    Use the following steps to fetch dependencies and run tests:
    
    ```yaml
          - run: flutter pub get
          - run: flutter test
    ```
    
5. Build the Android APK
    
    Build the Android APK for your Flutter application in debug mode:
    
    ```yaml
          - run: flutter build apk --debug --split-per-abi
    ```
    
6. Build the iOS IPA
    
    For iOS, we generate IPA as following:
    
    ```yaml
          - run: |
              flutter build ios --no-codesign
              cd build/ios/iphoneos
              mkdir Payload
              cd Payload
              ln -s ../Runner.app
              cd ..
              zip -r app.ipa Payload
    ```
    

Push the artifacts to GitHub releases

Finally, we use the `ncipollo/release-action` action to package the built artifacts (APK and IPA) and create a GitHub release. It will also tag the release with a version number.

```yaml
      - name: Push to Releases
        uses: ncipollo/release-action@v1
        with:
          artifacts: "build/app/outputs/apk/debug/*,build/ios/iphoneos/app.ipa"
          tag: v1.0.${{ github.run_number }}
          token: ${{ secrets.TOKEN }}
```

The `TOKEN` secret should be set up in your repository's settings with appropriate permissions to create releases.

### Pipeline overview

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1699437471108/ccfe2b56-a891-42b8-b6a8-46815e48dbae.png align="center")

We can view the pipeline in the actions tab of the GitHub repo. After successful completion, it should look something as shown above. And, the release section becomes:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1699452763498/254f4908-01b2-4b6b-ad22-17a502e0f10f.png align="center")

And when you click on the particular release, you get to the artifacts.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1699452837779/52ef53ef-896f-424e-905d-f1d53fbcf3ef.png align="center")

This is how the CI/CD pipeline is implemented for Flutter app using GitHub actions.

This article mainly focused on the Continuous Integration(CI) part, the Continuous Delivery(CD) part can be implemented using Fastlane for Appstore and Playstore, which will be discussed in future articles.
