- Published on
Effortless Flutter CI/CD with Codemagic & AWS
- Authors

- Name
- Phat Tran
Codemagic Setup for Acme App
Build, sign, and ship your Mono-repo Flutter super-app with one tag push - then relax and enjoy a coffee. 🚀 All you need is one Git tag that matches build/<env>-vX.Y.Z+N
Project Overview
Our Flutter project Acme App is hosted on AWS CodeCommit and has three parallel environments:
UATSTAGINGPRODUCTION
A build is triggered when a tag is pushed with the format:
build/<env>-v{versionNumber}+{buildNumber}
# Example
build/uat-v2.5.0+120
- Android → published to Firebase App Distribution
- iOS → uploaded to TestFlight
1. Connecting AWS CodeCommit to Codemagic
| Step | Action |
|---|---|
| 1 | Log in to Codemagic → Add application |
| 2 | Choose Other → Connect via SSH, paste your repo's SSH URL, select Flutter |
| 3 | Follow the official guide Connecting repository via SSH to create an SSH key pair. Add the public key to AWS IAM, store the private key in Codemagic |
| 4 | In CodeCommit → Settings → Triggers, add a Webhook that points to the Codemagic endpoint. See Setting up webhooks for AWS CodeCommit |
2. Link Codemagic ↔ Apple Developer Portal
- Open Teams → General settings → Team integrations
- Click Developer Portal → Connect
- Upload an App Store Connect API Key (recommended) or sign in with Apple ID
3. Upload iOS Code-Signing Assets
- Teams → Code signing identities
- iOS certificates → upload Distribution Certificate (
.p12) - iOS provisioning profiles → upload Distribution Profile (
.mobileprovision)
- iOS certificates → upload Distribution Certificate (
Codemagic decrypts and installs these during every iOS build.
4. Global Variables & Secret Groups (optional but tidy)
Teams → Global variables and secrets
| Group | Keys | Purpose |
|---|---|---|
| firebase_credentials | FIREBASE_SERVICE_ACCOUNT | Publish Android builds to Firebase |
| Telegram | TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_TOPIC_ID | Chat notifications |
All values are AES-encrypted and redacted from logs.
5. codemagic.yaml
Create the file in your repo root. Add the workflow below (Android-UAT).
Copy-paste and tweak the few flavour-specific lines for Staging and Production.
workflows:
android-uat-workflow:
name: android-acme-app-uat
instance_type: mac_mini_m2
max_build_duration: 120
environment:
groups:
- firebase_credentials
- Telegram
vars:
PACKAGE_NAME: 'com.acme.app.uat'
APP_SCHEME: 'uat'
JAVA_TOOL_OPTIONS: '-Xmx5g'
flutter: 3.13.3
triggering:
events:
- tag
tag_patterns:
- pattern: 'build/uat-*'
include: true
scripts:
- name: Initialize development environment
script: |
flutter pub global activate melos
flutter pub global run melos clean
flutter pub global run melos bootstrap
sh gen.sh
- name: Configure script permissions
script: |
chmod +x ./scripts/*.sh
- name: Process version tag
script: |
./scripts/cicd_extract_tag.sh
- name: Build UAT APK
script: |
cd apps/mobile_app
if flutter build apk --release \
--flavor uat \
--build-name=$APP_BUILD_VERSION \
--build-number=$APP_BUILD_NUMBER; then
echo "BUILD_STATUS=success" >> $CM_ENV
else
echo "BUILD_STATUS=failed" >> $CM_ENV
exit 1
fi
artifacts:
- apps/mobile_app/build/**/outputs/**/*.apk
- apps/mobile_app/build/**/outputs/**/mapping.txt
- flutter_drive.log
publishing:
firebase:
firebase_service_account: $FIREBASE_SERVICE_ACCOUNT
android:
app_id: 1:702077598571:android:857d8fea89643f3c6baa2e
groups:
- all
artifact_type: 'apk'
scripts:
- name: Send SMS to Telegram
script: |
./scripts/cicd_send_sms_telegram.sh
ios-uat-workflow:
name: ios-acme-app-uat
instance_type: mac_mini_m2
max_build_duration: 120
integrations:
app_store_connect: Acme Codemagic App Manager API Key
environment:
ios_signing:
distribution_type: app_store
bundle_identifier: com.acme.app.uat
vars:
APP_ID: 6476961138
APP_SCHEME: 'uat'
groups:
- Telegram
flutter: 3.13.3
xcode: 16.2
cocoapods: default
triggering:
events:
- tag
tag_patterns:
- pattern: 'build/uat-*'
include: true
scripts:
- name: Configure Xcode code signing
script: |
xcode-project use-profiles
- name: Initialize development environment
script: |
flutter pub global activate melos
flutter pub global run melos clean
flutter pub global run melos bootstrap
sh gen.sh
- name: Configure script permissions
script: |
chmod +x ./scripts/*.sh
- name: Process version tag
script: |
./scripts/cicd_extract_tag.sh
- name: Install Flutter dependencies
script: |
cd apps/mobile_app
flutter pub get
- name: Setup iOS dependencies
script: |
cd apps/mobile_app/ios
pod deintegrate
pod install --repo-update
- name: Build UAT IPA
script: |
cd apps/mobile_app
if flutter build ipa --release \
--build-name=$APP_BUILD_VERSION \
--build-number=$APP_BUILD_NUMBER \
--export-options-plist=/Users/builder/export_options.plist \
--flavor uat; then
echo "BUILD_STATUS=success" >> $CM_ENV
else
echo "BUILD_STATUS=failed" >> $CM_ENV
exit 1
fi
artifacts:
- apps/mobile_app/build/ios/ipa/*.ipa
- $CM_BUILD_DIR/build/ios/ipa/*.ipa
- /tmp/xcodebuild_logs/*.log
- flutter_drive.log
publishing:
app_store_connect:
auth: integration
submit_to_testflight: true
scripts:
- name: Send SMS to Telegram
script: |
./scripts/cicd_send_sms_telegram.sh
What do these keys do?
instance_type- Apple Silicon for faster builds.triggering.tag_patterns- only tags that matchbuild/uat-*run this workflow.artifacts- everything kept after the VM self-destructs.publishing.firebase- one-click deploy to testers.publishing.scripts- post-deploy actions (Telegram, JIRA, GitHub Release...).
Push a tag like build/uat-v2.5.0+120, watch Codemagic do its magic.