Setting Up GitLab CI/CD for Automated Builds Flutter Mobile App | by Maulana Firdaus | Mar, 2025

Setting up a .gitlab-ci.yml file in the root directory enables GitLab to automatically detect and execute CI/CD pipelines. This guide walks through the setup, including best practices for defining runners, handling sensitive data, selecting the correct Docker image, and ensuring a streamlined build process.

Before configuring the CI/CD pipeline, you need to ensure that a GitLab Runner is available. If a runner is not yet set up, ask the SRE (Site Reliability Engineering) team for assistance in registering a runner.

To verify a runner is available:
1. Go to GitLab Project → Settings → CI/CD → Runners.
2. Ensure at least one runner is active and assigned to your project.

If a runner is missing, request SRE support to register one.

Never store sensitive information in the GitLab CI/CD YAML file. Instead, use GitLab CI/CD variables:

  1. Navigate to GitLab Project → Settings → CI/CD → Variables.
  2. Add the required secret values (e.g., keystore files, API keys).
  3. Use the following method to decode Base64-encoded files:
  • echo $YOUR_GITLAB_CI_VARIABLE | base64 -di > your-file-name.extension
  1. Example: Decoding a Keystore file:
  • echo $KEYSTORE_FILE | base64 -di > mykeystore.jks

If needed, use this tool to encode files into Base64 format: File to Base64 Tool.

Ensure that the Docker image used in GitLab CI/CD matches the local development environment. You can find official images on Docker Hub or use an internally cloned image for faster builds.

Example:

image: ghcr.io/cirruslabs/flutter:3.27.1

Consider cloning the image to your private server to reduce external dependencies.

  • Use rules Instead of only or except (deprecated in GitLab 13.2+).
  • Use tags: to ensure the pipeline is executed by an appropriate runner.
  • Avoid Multi-line Commands: GitLab CI/CD does not support multi-line scripts. Use ; to separate commands.

Example of an optimized script:

script:
- apt-get update && apt-get install -y curl gnupg; \
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -; \
apt-get install -y nodejs; \
npm install -g firebase-tools; \
firebase --version

Use Git tags to generate build versions dynamically. The tag format follows:

[project-type]-[build-type]-[version]-[file-type]

Examples:

  • gen-integ-10020304-apk → Version 1.2.3.4-integ, builds an APK.
  • gen-prod-100203-aab → Version 1.2.3, builds an AAB.

The build script extracts version details using shell commands:

script:
- BUILD_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 2)
- BUILD_NUMBER=$(echo $CI_COMMIT_TAG | cut -d '-' -f 3)
- FILE_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 4)
image : ghcr.io/cirruslabs/flutter:3.27.1
stages:
- build
variables:
APK_OUTPUT_DIR: "build/app/outputs/flutter-apk"
AAB_OUTPUT_DIR: "build/app/outputs/bundle/release"
FIREBASE_APP_ID: ""
APP_ALIAS: ""
BUILD_NAME: ""
BUILD_NUMBER: ""
FILE_TYPE: ""
before_script:
- cd android
- echo $KEYSTORE_FILE | base64 -di > mykeystore.jks
- echo $KEY_PROPERTIES | base64 -di > key.properties
- cd ..
- flutter --version
- flutter pub get
- apt-get update && apt-get install -y curl gnupg
- curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
- apt-get install -y nodejs
- npm install -g firebase-tools
- firebase --version
build:
stage: build
script:
- echo "Parsing tag $CI_COMMIT_TAG...";
- BUILD_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 2);
- BUILD_NUMBER=$(echo $CI_COMMIT_TAG | cut -d '-' -f 3);
- FILE_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 4);
- if [[ "$BUILD_TYPE" == "prod" && ${#BUILD_NUMBER} -ne 6 ]]; then echo "Invalid build number for prod"; exit 1; fi;
- if [[ "$BUILD_TYPE" != "prod" && ${#BUILD_NUMBER} -ne 8 ]]; then echo "Invalid build number for integ/sbx"; exit 1; fi;
- flutter build $FILE_TYPE --release --build-name=$BUILD_NAME --build-number=$BUILD_NUMBER;
- if [[ "$FILE_TYPE" == "apk" ]]; then firebase appdistribution:distribute $APK_OUTPUT_DIR/app-release.apk --app $FIREBASE_APP_ID --token $FIREBASE_TOKEN --groups testers; fi;
artifacts:
paths:
- $APK_OUTPUT_DIR/app-release.apk
- $AAB_OUTPUT_DIR/app-release.aab
expire_in: 1 week
rules:
- if: '$CI_COMMIT_TAG =~ /.*-apk|.*-aab/'
tags:
- build

This guide outlines best practices for setting up a GitLab CI/CD pipeline, securely managing sensitive data, and optimizing build scripts. By following these steps, your project will have a consistent, efficient, and automated deployment process.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.