Have you ever experienced waiting long hours to deploy a build of your app, only to know in the end, it failed because of that one little mistake that you did?

You forgot to run the tests, code sign the project, or clean the project before creating a build. Even worse, you’re in a hurry that you failed to submit the build. 🤦

These issues are some of the things that you have to deal with repeatedly, whenever you manually deploy your Flutter apps (Android and iOS) to Google Play or Apple App Store, respectively.

Get help

Start automating your workflow.

Here’s some of the benefits you get when you automate your workflow:

  • Quality - without sacrificing developer productivity, your team is enabled to ship a product that gets tested several times against multiple edge cases and environments
  • Timeliness - automated workflow makes it easy for your team to plan release schedules ahead of time or ship bug fixes quickly to production
  • Reproducible builds - you can easily track and fix issues found on a specific build

CI/CD in a nutshell

“CI” in CI/CD stands for Continuous Integration, it always has been. While the “CD” may either refer to Continuous Delivery or Continuous Deployment.

ci/cd

Typical CI/CD setup of a project

CI/CD contains a set of jobs for automating your development and deployment workflow.

CI jobs are used for running the pre-checks whether a new code can be merged into a repository. These jobs include but are not limited to running lint checks, tests, and building your app.

Continuous delivery and continuous deployment are almost identical. They both extend the CI jobs and prepare your app for release, except when deploying it.

Continuous deployment automatically deploys the changes of your app to production, while continuous delivery doesn’t. This means that with continuous delivery, your team gets to decide when to “manually” release the build.

Continuous Delivery vs Continuous Deployment

Which one is preferred? It depends.

They both have varying pros and cons depending on the project requirement or organization structure.

From my experience as a release manager at Freelancer.com, the mobile team uses a continuous delivery workflow. It makes sense because some internal processes require manual intervention before a build can be considered as “ready for production”.

In this article series, your goal is to implement a continuous delivery workflow.

Several CI/CD tools are available to help you automate your workflow, but using Github Actions and Fastlane is a good starting point to learn CI/CD.

Github Actions

Github Actions is a service that allows you to run your CI/CD workflow in the cloud.

Using this service, you rely on actions that are created by the community. You can also create your custom action by following this guide.

Pricing

Public Repositories

  • Free

Private Projects

  • Free: 2,000 Action minutes/month
  • Team: 3,000 Action minutes/month
  • Enterprise: 50,000 Action minutes/month

Demo

Here’s a simple demo the using CI workflow in Github Actions:

ci/cd

This is the workflow file used for the demo shown above:

# ci.yml

name: CI

on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-java@v1
        with:
          java-version: 12.x
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: 1.17.5
      - run: flutter pub get
      - run: flutter format --set-exit-if-changed .
      - run: flutter analyze .
      - run: flutter test
      - run: flutter build apk
      - uses: actions/upload-artifact@v1
        with:
          name: release-apk
          path: build/app/outputs/apk/release/app-release.apk

Core Concepts 💡

Workflow

A workflow is triggered (to run) by a specific event. In the example above, the on parameter indicates that this workflow is triggered, whenever you push new commits to the master branch.

Job

By default, a job runs in parallel with the other tasks you specified in the jobs. This is helpful for a Flutter project because you can run simultaneous jobs when building your Android and iOS apps.

ci/cd

You can also run a set of jobs sequentially by using the needs parameter, which accepts the name of the jobs it depends on.

# example_sequential_jobs.yml

jobs:
  build_android:
    steps: ...
  deploy_android:
    needs: [build_android]
    steps: ...

In the example, if build_android job fails, deploy_android will not run.

Step

steps contains a combination of multiple commands and actions to fulfill a job.

Action

These are the individual tasks combined to create a step. In a task, you specify the Github Action package you need, the executable commands to run, or the configuration of the task such as setting the environment variables.

# example_environment_variables.yml
- uses: subosito/flutter-action@v1
  with:
    flutter-version: 1.17.5
  env:
    SOME_SECRET: "${{ secrets.SOME_SECRET }}"

Github provides a secure way to store these encrypted secrets so you can use them inside a workflow file without having to hardcode them in your code.

ci/cd

Fastlane

At the time of writing, there’s no easy way of uploading the builds of your Flutter apps to Google Play Console (Android) or TestFlight (iOS) by using Github Actions alone.

Fastlane to the rescue.

Fastlane is an open-source tool that simplifies the deployment of both Android and iOS apps.

It comes with Fastlane match which makes it easy for teams to generate certificates and provisioning profiles when building iOS apps. More on this on the follow-up article for the iOS setup.

Fastlane determines the configuration of your automated workflow using a Fastfile. This contains the Fastlane actions used to upload both Android and iOS builds to Google Play and TestFlight respectively.

Here’s a snippet of a Fastfile for an iOS app:

default_platform :ios
platform :ios do

  desc "This lane builds and upload the iOS app to the AppStore"
  lane :build_and_upload do
    custom_ruby_function
    build_ios_app
    upload_to_app_store
  end

  def custom_ruby_function():
    ...
  end
end

Core Concepts 💡

Lane

build_and_upload is an example of a lane. This consists of the Fastlane actions or custom Ruby functions required to complete a job.

Fastlane Actions

build_ios_app and upload_to_app_store are both examples of Fastlane actions. These are the functions that are included in Fastlane by default. More on the available Fastlane actions here.

Workflow setup goal

ci/cd

Continuous Delivery using Fastlane and Github Actions

Github Actions will be used to run the entire CI/CD workflow, invoke Flutter commands such as running tests and creating artifacts, and execute the lanes described in the Fastfiles.

Implement the workflow

Continue reading the follow-up articles in this series:

Conclusion

The benefit you get from your CI/CD workflow is often directly proportional to your investment in it.

Starting small is still a good thing than not having anything set up at all.

Having an automated workflow saves a lot of time spent on waiting, helps avoid frustration on silly mistakes, lets your team focus on what matters, and be productive. 🚀

Resources