Setting Up CI/CD for Flutter Apps With Codemagic
Automate Everything: Setting Up Flutter CI/CD Using Codemagic
In modern mobile app development, shipping features quickly without sacrificing quality is the ultimate competitive advantage. Setting up a robust cicd flutter codemagic pipeline allows engineering teams to automate the entire lifecycle of their applicationβfrom linting and testing to building, signing, and deploying. Instead of spending hours manually generating .ipa and .apk files on local machines, developers can commit code and let cloud infrastructure handle the heavy lifting.
When building cross-platform apps, as we discussed in our deep dive on why Flutter is the premier choice for cross-platform development, maintaining a single codebase is only half the battle. You also need a unified delivery pipeline. Codemagic stands out as the premier CI/CD tool tailored specifically for Flutter, offering out-of-the-box macOS build environments, seamless integration with App Store Connect and Google Play Console, and a highly customizable configuration-as-code model.
Why Automated Pipelines are Vital for Fast Iterations
Manual deployment is a silent killer of developer productivity. It introduces human error, creates "it works on my machine" bottlenecks, and consumes valuable engineering hours.
Consider the traditional, manual release process:
- A developer pulls the latest code and runs tests locally.
- They switch to a physical Mac to build the iOS archive, dealing with outdated provisioning profiles and certificates.
- They build the Android App Bundle (AAB) using a local keystore file that is insecurely shared over Slack or stored on a shared drive.
- They manually upload the builds to App Store Connect and Google Play Console via web interfaces.
This manual approach is fragile and slow. Implementing a cicd flutter codemagic pipeline eliminates these friction points by standardizing the build environment in the cloud.
[ Developer Commits Code ]
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Codemagic CI/CD Pipeline β
β β
β 1. Lint & Static Analysis β
β 2. Run Unit & Widget Tests β
β 3. Auto-Increment Build Version β
β 4. Secure Code Signing (iOS & Android) β
β 5. Build Release Binaries (IPA & AAB) β
βββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββ
βΌ βΌ
βββββββββββββββββββββ βββββββββββββββββββββ
β Apple TestFlight β β Google Play Track β
βββββββββββββββββββββ βββββββββββββββββββββ
Manual vs. Automated Deployment Comparison
| Feature | Manual Deployment | Codemagic CI/CD Pipeline | | :--- | :--- | :--- | | Build Environment | Local machine (inconsistent OS/SDK versions) | Clean, ephemeral cloud VMs (macOS/Linux) | | Code Signing | Manual certificate management in Xcode/Gradle | Automated, secure cloud-based signing | | Testing | Often skipped or run manually before commits | Executed automatically on every Pull Request | | Release Velocity | Hours or days per release | Minutes, triggered automatically on git push | | Security | Keystores and API keys stored on local disks | Encrypted environment variables |
By adopting flutter build automation, your team can focus entirely on writing feature code, confident that the integration and delivery pipeline will catch bugs and deliver binaries to stakeholders automatically.
Configuring the Codemagic YAML File
While Codemagic offers a visual user interface for configuring builds, managing your pipeline as code using a codemagic.yaml file is the industry best practice. It ensures your pipeline configuration is version-controlled, peer-reviewed, and easily replicable across different projects.
To get started, create a file named codemagic.yaml in the root directory of your Flutter project. Below is a production-ready template that we will break down step-by-step.
workflows:
flutter-release-pipeline:
name: Flutter Release Pipeline
max_build_duration: 60
instance_type: mac_mini_m1
environment:
groups:
- keystore_credentials
- app_store_credentials
vars:
XCODE_SCHEME: "Runner"
XCODE_WORKSPACE: "ios/Runner.xcworkspace"
flutter: stable
xcode: latest
cocoapods: defaultDefining Build Triggers and Environment Variables
To make your codemagic workflow highly efficient, you must define exactly when builds should run. Running a full release build on every single commit to a feature branch is a waste of resources. Instead, you should trigger lightweight testing workflows on Pull Requests, and full deployment workflows only when code is merged into the main or release branches.
Here is how you configure automatic build triggers in your codemagic.yaml:
triggering:
events:
- push
- pull_request
branch_patterns:
- pattern: 'main'
include: true
source: true
- pattern: 'release/*'
include: true
source: true
cancel_previous_builds: trueIn this configuration:
events: The pipeline triggers on both code pushes and pull requests.branch_patterns: We target themainbranch and any release branches (e.g.,release/v1.0).cancel_previous_builds: If a developer pushes a new commit while a build is already running for an older commit on the same branch, Codemagic automatically cancels the redundant build, saving build minutes.
Setting Up Automated Versioning
Managing build numbers manually in pubspec.yaml is tedious and prone to merge conflicts. A robust flutter build automation pipeline should dynamically calculate and inject the build number at runtime.
We can achieve this by using the build number provided by Codemagic's environment variables ($BUILD_NUMBER) and passing it directly to the Flutter build command.
scripts:
- name: Set up local properties and versioning
script: |
# Calculate build version based on Codemagic build number
BUILD_NAME="1.0.0"
BUILD_NUMBER=$(($BUILD_NUMBER + 100)) # Offset if migrating from another system
echo "Building version $BUILD_NAME+$BUILD_NUMBER"
# Write version to an environment file for subsequent steps
echo "BUILD_NAME=$BUILD_NAME" >> $FCI_ENV_DIR/env_vars
echo "BUILD_NUMBER=$BUILD_NUMBER" >> $FCI_ENV_DIR/env_varsLater in the build step, we reference these variables:
- name: Build Android App Bundle
script: |
flutter build appbundle \
--release \
--build-name=$BUILD_NAME \
--build-number=$BUILD_NUMBERAutomated Code Quality: Testing and Linting Pipelines
Before compiling binaries for distribution, your pipeline must verify that the codebase meets your team's quality standards. This prevents broken code or unformatted files from reaching production.
We configure a series of scripts to run static analysis, check code formatting, and execute unit and widget tests.
scripts:
- name: Get Flutter Packages
script: |
flutter pub get
- name: Check Code Formatting
script: |
flutter format --set-exit-if-changed lib/
- name: Run Static Analysis (Linter)
script: |
flutter analyze
- name: Run Unit and Widget Tests
script: |
flutter test --coverageWhy These Steps Matter:
flutter format --set-exit-if-changed: This command checks if all Dart files conform to the official style guide. If a developer forgot to format their code before committing, the command exits with a non-zero status, failing the build immediately.flutter analyze: This runs the compiler's static analyzer to catch potential runtime bugs, unused imports, or deprecated API usage.flutter test --coverage: This runs your entire suite of unit and widget tests and generates a LCOV coverage report. You can integrate this with third-party tools like Codecov or SonarQube to track test coverage trends over time.
Code Signing Made Easy: Auto-Signing iOS and Android Apps
Code signing is historically the most complex and frustrating part of mobile app deployment. Fortunately, Codemagic simplifies this process significantly for both platforms.
Android Code Signing
To sign your Android App Bundle (AAB) or APK, you need a Java Keystore file (.jks). You should never commit this file directly to your git repository. Instead, encode the keystore file to base64 and store it as a secure environment variable in Codemagic.
To convert your keystore to base64 locally, run:
openssl base64 -in my-release-key.jks -out keystore_base64.txtCopy the contents of keystore_base64.txt and add it to Codemagic as a secure environment variable named ANDROID_KEYSTORE_BASE64. Also add ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, and ANDROID_KEY_PASSWORD.
In your codemagic.yaml, decode the keystore file dynamically during the build:
- name: Set up Android Keystore
script: |
echo $ANDROID_KEYSTORE_BASE64 | base64 --decode > /tmp/keystore.jks
# Create key.properties file for Gradle to read
cat <<EOF > android/key.properties
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyPassword=$ANDROID_KEY_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
storeFile=/tmp/keystore.jks
EOFEnsure your android/app/build.gradle is configured to read from this key.properties file:
def keystorePropertiesFile = rootProject.file('key.properties')
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
...
signingConfigs {
release {
if (keystorePropertiesFile.exists()) {
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}iOS Code Signing
The beauty of a cicd flutter codemagic setup is its native integration with Apple's App Store Connect API. Codemagic can automatically generate signing certificates and fetch provisioning profiles on the fly.
To set this up:
- Generate an App Store Connect API Key in your Apple Developer Account (Users and Access > Integrations > App Store Connect API).
- Save the Issuer ID, Key ID, and the
.p8private key file content as secure environment variables in Codemagic (APP_STORE_CONNECT_ISSUER_ID,APP_STORE_CONNECT_KEY_ID,APP_STORE_CONNECT_PRIVATE_KEY).
Add the following configuration to your codemagic.yaml to enable automatic iOS code signing:
environment:
groups:
- app_store_credentials
scripts:
- name: Set up iOS Code Signing
script: |
keychain initialize
app-store-connect fetch-signing-files "com.example.myflutterapp" \
--platform IOS_APP_DEVELOPMENT \
--type PROFILE_TYPE_IOS_APP_STORE \
--create
keychain add-certificatesThis script initializes a temporary macOS keychain, authenticates with Apple using your API key, downloads the correct distribution certificates and provisioning profiles, and installs them onto the build machine.
Automatic Publishing to TestFlight and Google Play Console
Once your application is built and signed, the final step in your automate app store deploy flutter strategy is pushing the binaries to the respective app stores.
publishing:
email:
recipients:
- dev-team@vyrova.tech
notify:
success: true
failure: true
google_play:
credentials: $GP_SERVICE_ACCOUNT_JSON
track: internal # Options: internal, alpha, beta, production
submit_as_draft: false
app_store_connect:
auth: integration # Uses the App Store Connect integration configured in Codemagic UI
submit_to_testflight: true
beta_groups:
- External TestersGoogle Play Publishing Requirements
To publish to Google Play, you must generate a Service Account JSON key in your Google Cloud Console linked to your Google Play Console. Store this entire JSON string in a secure environment variable named GP_SERVICE_ACCOUNT_JSON. Codemagic will use this key to authenticate and upload your .aab file directly to the specified track (e.g., internal for immediate QA testing).
App Store / TestFlight Publishing Requirements
By setting submit_to_testflight: true, Codemagic uploads your signed .ipa file directly to Apple's servers. Once Apple finishes processing the build, it will automatically distribute it to the specified beta_groups in TestFlight.
Looking for Premium Mobile App Developers?
We build high-performance, native-grade cross-platform apps using Flutter and React Native. Let's discuss your product goals.
Conclusion: A Fully Automated Delivery Pipeline
With your cicd flutter codemagic pipeline fully configured, your development workflow is completely transformed. Every time a developer pushes code to your repository:
- The code is formatted and analyzed for potential bugs.
- Unit and widget tests run to ensure no regressions are introduced.
- The build version is automatically calculated and incremented.
- Secure, cloud-based code signing is executed for both iOS and Android.
- Production-ready binaries (
.ipaand.aab) are compiled. - The builds are automatically uploaded to Apple TestFlight and Google Play Console.
This level of automation eliminates human error, ensures consistent build environments, and dramatically accelerates your release cycles. Investing the time to set up a professional CI/CD pipeline today pays massive dividends in product quality and developer happiness tomorrow.
