CI/CD & Distribution
Release in minutes. Hotfix in hours.
We automate the entire release pipeline for mobile applications — build, testing, signing, upload to Store. No manual steps.
Why Automated Mobile CI/CD¶
A mobile release is not like a web deploy. You can’t rollback a deployment in seconds. App Store review takes hours to days. Signing certificates, provisioning profiles, keystores — every manual step is a potential failure.
Without automation, release is a painful process that the team keeps postponing. Features pile up in the develop branch, releases happen once a month, hotfixes go “with the next release.” Result: slow feedback loop, frustrated users, unhappy developers.
Automated pipeline: Merge to main → automatic build → tests → signing → upload to Store → team notification. The entire process with one click (or zero clicks with auto-deploy).
Fastlane Pipeline¶
Fastlane is the de facto standard for automating mobile CI/CD. A Ruby-based toolchain that orchestrates the entire release process.
iOS Pipeline¶
lane :release do
increment_build_number
run_tests(scheme: "AppTests")
match(type: "appstore") # certificate management
gym(scheme: "App") # build
pilot(skip_waiting: true) # upload to TestFlight
upload_to_app_store # App Store release
end
Match for certificate management: Provisioning profiles and signing certificates stored in an encrypted Git repository. Every developer and CI machine shares the same credentials. No “I can’t build” — fastlane match downloads and installs everything needed.
Metadata as code: App Store metadata (screenshots, descriptions, release notes, keywords) versioned in Git. Localization for multiple languages. Review screenshots generated automatically from UI tests (fastlane snapshot).
Android Pipeline¶
lane :release do
increment_version_code
gradle(task: "test")
gradle(task: "assembleRelease")
supply(track: "internal") # upload to Google Play
end
Keystore management: Signing keystore in secure storage (CI secrets, Vault). Upload key vs. app signing key separated (Google Play App Signing).
Bundle vs APK: Android App Bundle (AAB) as default — Google Play generates optimized APK per device. Smaller download, faster installation.
CI/CD Infrastructure¶
Build Servers¶
- GitHub Actions: Self-hosted macOS runners for iOS builds. Linux runners for Android. Matrix build for multiple SDK versions.
- Bitrise: Managed CI for mobile development. macOS machines for iOS, Docker for Android. Integrated with Fastlane.
- Xcode Cloud: Apple’s CI/CD. Integrated with App Store Connect. Limitation: iOS/macOS only.
Pipeline Stages¶
- Lint & Static Analysis — SwiftLint, Detekt, ktlint. Automatic code style enforcement.
- Unit Tests — Fast, isolated. Runs on every push. Fail = blocked merge.
- Integration Tests — API contract tests, database tests. Runs on PR merge.
- UI Tests — E2E flows on simulator/emulator. Runs on PR merge and nightly.
- Build — Debug for PR, Release for main/release branch.
- Sign — Automatic signing with Match (iOS) / Keystore (Android).
- Upload — TestFlight/Firebase App Distribution for beta, Store for release.
- Notify — Slack/Teams notifications with build status and QR code for installation.
Parallelization: iOS and Android builds run in parallel. Tests parallelized (sharded). Entire pipeline under 15 minutes.
Beta Distribution¶
TestFlight (iOS)¶
Apple’s official beta testing platform:
- Internal testing: build available immediately for the team (up to 100 testers)
- External testing: App Store Connect review (typically <24h), up to 10,000 testers
- Automatic build upload after merging to develop
- Feedback directly in the app — screenshot + annotation + device info
Firebase App Distribution (Android + iOS)¶
- Distribution outside Store — direct download via link or QR code
- Tester groups — QA, stakeholders, beta users
- Release notes per build
- SDK for in-app feedback
In-app Feedback¶
Tester shakes the phone (shake gesture) → feedback form opens:
- Screenshot with annotation option (arrows, rectangles, text)
- Automatically attached: device info, OS version, app version, network status, logs
- Submission to Jira/Linear/GitHub Issues
- Significantly faster feedback loop than “send me a screenshot via email”
OTA Updates (CodePush)¶
When OTA¶
For React Native and Flutter applications: JavaScript/Dart bundle update without Store review. Hotfix in production in minutes, not days.
What OTA can do: UI changes, business logic in JS/Dart, content updates, bug fixes in managed code.
What OTA cannot do: Native code (Swift/Kotlin modules), new native dependencies, native SDK updates.
Staged Rollout¶
We never rollout an OTA update to 100% of users at once:
- Canary (1-5%) — minimal group, monitoring crash rate and error rate
- Early adopters (10-20%) — broader validation, business metrics
- General availability (100%) — after confirming stability
Automatic rollback: if crash rate rises by >X% compared to baseline, the OTA update is automatically pulled and users get the previous version.
Store Staged Rollout¶
- Google Play: Percentage rollout (0.1% → 1% → 5% → 20% → 50% → 100%). Monitoring crash-free rate in Google Play Console. Halt and rollback at any time.
- iOS Phased Release: 7-day gradual rollout (1% → 2% → 5% → 10% → 20% → 50% → 100%). Halt at any time. Immediate release for critical updates.
Post-release Monitoring¶
Release doesn’t end with an upload to the Store. Post-release monitoring is critical:
Crash Reporting¶
- Crashlytics (Firebase): Real-time crash reporting with stack traces, device info, breadcrumbs. Automatic grouping of similar crashes. Alerting on spikes.
- Sentry: More detailed error tracking with custom context. Performance monitoring (transaction tracing). Release health dashboard.
Performance Monitoring¶
- Startup time: Cold start, warm start. Trend across versions.
- Frame rendering: Frozen frames, slow frames. Jank detection.
- Network: API latency, error rate, payload size per endpoint.
- Battery and memory: Excessive battery drain, memory leaks, disk usage.
Forced Update¶
For critical security patches — the app displays a dialog: “Please update to the latest version.” Configurable: soft update (dismiss possible) vs. hard update (blocks usage). Minimum version check at every app start.
Technology Stack¶
CI/CD: Fastlane, GitHub Actions, Bitrise, Xcode Cloud, Gradle.
Distribution: TestFlight, Firebase App Distribution, Google Play Console, App Store Connect.
OTA: CodePush (App Center), Expo Updates, Shorebird (Flutter).
Monitoring: Crashlytics, Sentry, Firebase Performance, Google Play Vitals, App Store Connect Analytics.
Signing: Fastlane Match, Android Keystore, Google Play App Signing.
Časté otázky
Via CodePush/OTA: minutes. Via Store: hours (Android), hours to days (iOS review). For critical bugs we have an OTA path, for native changes the Store path with expedited review.
CodePush allows updating the JavaScript bundle of a React Native app without Store review. Ideal for hotfixes, content changes, UI tweaks. Cannot be used for native code — that requires a Store update.
Fastlane Match for iOS — shared certificates and provisioning profiles in an encrypted Git repo. Keystore management for Android. No 'I can't build, I don't have the certificate'.
Yes. Google Play staged rollout (1% → 10% → 50% → 100%) with automatic crash rate evaluation. iOS phased release (7 days). Rollback at any time before 100%.