On This Page
1Overview2Pipeline Stages
3Code Signing4Anti-Patterns to Avoid
5References

Overview

Fastlane combined with GitHub Actions is the Ascendion standard for mobile CI/CD (specified in ADR-MOB-003). Fastlane handles mobile-specific automation — code signing, building, testing, distribution, store submission. GitHub Actions orchestrates the workflow with matrix strategy for parallel Android and iOS builds.

Pipeline Stages

Stage 1: Validate (Every PR, ~8 minutes)

Lint (Detekt/SwiftLint), unit tests with coverage gate (Use Cases > 90%, ViewModels > 80%), snapshot test diff (zero pixel regressions), security scan (OWASP Dependency Check, GitLeaks). Runs on Linux runner for Android, macOS runner for iOS lint only (Swift compilation). Gate: block PR merge on any failure.

Stage 2: Build (Merge to Main, ~15 minutes)

Android: Gradle assembleRelease with R8 full mode. iOS: Xcode Archive with Release configuration. Parallel matrix: Android on ubuntu-latest, iOS on macos-latest. Post-build: code signing (Android Keystore decode from base64 secret; iOS fastlane match download from encrypted Git repo).

Stage 3: Test (Post-Build, ~10 minutes)

Integration tests with in-memory database. UI tests on emulator (Android) and simulator (iOS) for top 10 critical user journeys. Paparazzi/iOSSnapshotTestCase screenshot comparison. Runs after build to avoid blocking the main test loop.

Stage 4: Distribute (Post-Test, ~5 minutes)

Internal distribution: Firebase App Distribution for Android and iOS (both platforms). TestFlight for iOS internal testing. Automatic distribution to QA team. Deployment note generated from git log since last distribution.

Stage 5: QA Gate (Manual, ~24-48 hours)

GitHub Actions Environment Protection Rule on the Production environment requires QA Lead approval. QA tests on physical devices using the distributed build. No automated gate can replace human QA for the release candidate.

Stage 6: Release (Post-QA, ~10 minutes)

Android: fastlane supply uploads AAB to Google Play internal track, promotes to staged rollout (1% → 5% → 20% → 100% over 7 days). iOS: fastlane deliver uploads IPA to App Store Connect, submits for review. Automated release note generation from CHANGELOG.md.

Code Signing

iOS code signing is the most complex operational aspect of mobile CI/CD. fastlane Match solves it: all certificates and provisioning profiles stored encrypted in a dedicated Git repository. Every CI machine and developer clones them fresh using the Match passphrase (stored as MATCH_PASSWORD encrypted secret in GitHub). Certificate expiry handled automatically: Match regenerates certificates 30 days before expiry.

Android code signing: release Keystore encoded as base64 string stored as KEYSTORE_B64 encrypted secret. CI decodes to a temporary file, configures Gradle signingConfigs block reading credentials from environment variables, deletes the temporary file after signing. Enrolled in Google Play App Signing — Google manages the distribution key, protecting against Keystore loss.

Anti-Patterns to Avoid

⚠ 1. Manual Code Signing

Engineer manually downloading a Provisioning Profile from Apple Developer Portal, installing it, building locally, and uploading to TestFlight. Undocumented, unreproducible, fails when that engineer is unavailable.

Hover to see the fix ↻
↺ Correct Approach

fastlane Match. All signing materials in the encrypted repository. Any CI machine or developer with the passphrase can sign and release. Documented, reproducible, auditable.

⚠ 2. No QA Gate Before Production

Pipeline automatically promotes to production after passing automated tests.

Hover to see the fix ↻
↺ Correct Approach

GitHub Environment Protection Rule requiring QA Lead approval before any production release. Automated tests catch regressions; human QA catches usability, visual, and contextual issues automated tests miss.

Flowchart

%%{init:{'theme':'base','themeVariables':{'fontSize':'14px','fontFamily':'IBM Plex Sans, system-ui, sans-serif','primaryColor':'#DBEAFE','primaryTextColor':'#1e3a5f','primaryBorderColor':'#2563EB','lineColor':'#374151','clusterBkg':'#F9FAFB','clusterBorder':'#D1D5DB','edgeLabelBackground':'#FFFFFF'},'flowchart':{'curve':'orthogonal','padding':30,'nodeSpacing':65,'rankSpacing':75,'useMaxWidth':true}}}%% flowchart LR GIT["<b>git push</b><br/>to main"] subgraph VAL["Validate · &lt;8min"] direction TB L["Detekt · SwiftLint<br/>Zero violations"] U["Unit Tests<br/>90% Use Cases<br/>80% ViewModels"] S["Snapshot Diff<br/>Zero regressions"] SEC2["CVE Scan<br/>Block P1/P2"] end subgraph BUILD["Parallel Build"] direction TB AND["Android<br/>ubuntu-latest<br/>Gradle · R8"] IOS["iOS<br/>macos-latest<br/>Xcode Archive"] end subgraph SIGN["Sign"] direction TB KS["Android Keystore<br/>Base64 secret"] FM["fastlane Match<br/>Encrypted Git repo"] end DIST["Distribute<br/>Firebase · TestFlight"] QA{"QA Gate<br/>Manual approval"} subgraph SHIP["Release"] direction TB PL["Google Play<br/>1%→5%→25%→50%→100%"] AS["App Store<br/>Expedited review"] end GIT --> VAL --> BUILD --> SIGN --> DIST --> QA QA -->|"Approved"| SHIP QA -->|"Rejected"| GIT style GIT fill:#1D4ED8,stroke:#1e3a5f,color:#ffffff style VAL fill:#DCFCE7,stroke:#16A34A,stroke-width:2px style BUILD fill:#DBEAFE,stroke:#2563EB,stroke-width:2px style SIGN fill:#FEE2E2,stroke:#DC2626,stroke-width:2px style DIST fill:#FEF9C3,stroke:#CA8A04,stroke-width:2px style QA fill:#FEF3C7,stroke:#D97706,stroke-width:2px style SHIP fill:#F3E8FF,stroke:#7C3AED,stroke-width:2px style L fill:#BBF7D0,stroke:#16A34A,color:#14532D style U fill:#BBF7D0,stroke:#16A34A,color:#14532D style S fill:#BBF7D0,stroke:#16A34A,color:#14532D style SEC2 fill:#BBF7D0,stroke:#16A34A,color:#14532D style AND fill:#BFDBFE,stroke:#2563EB,color:#1e3a5f style IOS fill:#BFDBFE,stroke:#2563EB,color:#1e3a5f style KS fill:#FCA5A5,stroke:#DC2626,color:#7f1d1d style FM fill:#FCA5A5,stroke:#DC2626,color:#7f1d1d style PL fill:#E9D5FF,stroke:#7C3AED,color:#4C1D95 style AS fill:#E9D5FF,stroke:#7C3AED,color:#4C1D95

References

  1. Fastlane Documentation. docs.fastlane.tools
  2. GitHub Actions Documentation — Environments. docs.github.com/en/actions/deployment/targeting-different-environments
  3. Google — Play Console Staged Rollouts. support.google.com/googleplay/android-developer/answer/6346149
  4. Forsgren et al. — Accelerate. IT Revolution, 2018.
Mobile Engineering Reference
← Mobile Development