
How to Implement CI/CD Pipelines for Flutter, React Native and .NET MAUI

Continuous Integration and Continuous Deployment (CI/CD) pipelines have become essential for modern mobile app development. They automate testing, building, and deploying apps, ensuring consistent quality while reducing manual effort. This comprehensive guide will walk you through implementing effective CI/CD pipelines for three popular cross-platform frameworks: Flutter, React Native, and .NET MAUI.
Introduction to CI/CD for Mobile Development
CI/CD practices offer several significant benefits for mobile app developers:
- Faster release cycles: Automate time-consuming build and deployment processes
- Higher quality: Catch bugs early through automated testing
- Consistency: Ensure builds are reproducible across environments
- Team efficiency: Free developers from repetitive tasks
While the specific implementation details vary between frameworks, the core principles remain consistent: automate everything, test thoroughly, and deploy reliably.
Key CI/CD Platforms for Mobile Development
Before diving into framework-specific configurations, let's briefly examine the platforms we'll be working with:
GitHub Actions
- Tightly integrated with GitHub repositories
- Flexible workflow configuration via YAML
- Free tier for public repositories
- Growing mobile-specific action ecosystem
Bitrise
- Mobile-first CI/CD platform
- Extensive library of pre-built steps for mobile workflows
- Excellent support for code signing and provisioning
- Intuitive workflow editor
Azure DevOps
- Comprehensive DevOps toolchain
- Powerful integration with Microsoft services
- Flexible build agents and deployment targets
- Advanced pipeline configuration options
Let's now explore how to implement CI/CD for each framework.
Flutter CI/CD Implementation
Flutter's growing popularity for cross-platform development makes it an excellent candidate for CI/CD automation.
Setting Up GitHub Actions for Flutter
Create a .github/workflows/flutter-ci.yml
file in your repository:
name: Flutter CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.19.0"
channel: "stable"
- name: Install dependencies
run: flutter pub get
- name: Analyze project source
run: flutter analyze
- name: Run tests
run: flutter test
- name: Build APK
run: flutter build apk --release
- name: Upload APK
uses: actions/upload-artifact@v3
with:
name: release-apk
path: build/app/outputs/flutter-apk/app-release.apk
Bitrise Configuration for Flutter
- Add your Flutter project to Bitrise
- Use the Flutter App workflow template
- Configure your workflow with these key steps:
# bitrise.yml snippet
workflows:
primary:
steps:
- activate-ssh-key@4:
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
- git-clone@6: {}
- flutter-installer@0:
inputs:
- version: stable
- cache-pull@2: {}
- flutter-analyze@0:
inputs:
- project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
- flutter-test@0:
inputs:
- project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
- flutter-build@0:
inputs:
- project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
- platform: both
- deploy-to-bitrise-io@2: {}
- cache-push@2: {}
Azure DevOps Pipeline for Flutter
Create an azure-pipelines.yml
file with:
trigger:
- main
pool:
vmImage: "ubuntu-latest"
steps:
- task: FlutterInstall@0
inputs:
channel: "stable"
version: "latest"
- task: FlutterCommand@0
inputs:
projectDirectory: "."
command: "pub"
arguments: "get"
- task: FlutterCommand@0
inputs:
projectDirectory: "."
command: "analyze"
- task: FlutterTest@0
inputs:
projectDirectory: "."
- task: FlutterBuild@0
inputs:
projectDirectory: "."
target: "aab"
buildNumber: "$(Build.BuildNumber)"
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: "$(Build.SourcesDirectory)/build/app/outputs/bundle/release/app-release.aab"
ArtifactName: "android-bundle"
publishLocation: "Container"
React Native CI/CD Implementation
React Native remains extremely popular for JavaScript developers looking to build cross-platform mobile apps.
GitHub Actions for React Native
Create a .github/workflows/react-native-ci.yml
file:
name: React Native CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npx eslint .
- name: Run Jest tests
run: npm test
- name: Setup Java JDK
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Build Android Release
run: |
cd android
./gradlew bundleRelease
- name: Upload Android Bundle
uses: actions/upload-artifact@v3
with:
name: app-release-bundle
path: android/app/build/outputs/bundle/release/app-release.aab
Bitrise Configuration for React Native
Configure your bitrise.yml
with:
# bitrise.yml snippet for React Native
workflows:
primary:
steps:
- activate-ssh-key@4: {}
- git-clone@6: {}
- npm@1:
inputs:
- command: ci
- npm@1:
inputs:
- command: test
- android-build@1:
inputs:
- project_location: "$BITRISE_SOURCE_DIR/android"
- module: "app"
- variant: "release"
- deploy-to-bitrise-io@2: {}
- cache-push@2: {}
Azure DevOps Pipeline for React Native
Create an azure-pipelines.yml
file:
trigger:
- main
pool:
vmImage: "macos-latest"
steps:
- task: NodeTool@0
inputs:
versionSpec: "18.x"
displayName: "Install Node.js"
- script: |
npm ci
displayName: "Install dependencies"
- script: |
npm test
displayName: "Run tests"
- task: JavaToolInstaller@0
inputs:
versionSpec: "17"
jdkArchitectureOption: "x64"
jdkSourceOption: "PreInstalled"
- script: |
cd android
./gradlew bundleRelease
displayName: "Build Android Release"
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: "$(Build.SourcesDirectory)/android/app/build/outputs/bundle/release"
ArtifactName: "android-release"
publishLocation: "Container"
.NET MAUI CI/CD Implementation
Microsoft's .NET Multi-platform App UI (.NET MAUI) is the evolution of Xamarin.Forms, enabling you to build cross-platform apps with C# and XAML.
GitHub Actions for .NET MAUI
Create a .github/workflows/maui-ci.yml
file:
name: .NET MAUI CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-android:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: "8.0.x"
- name: Install MAUI Workload
run: dotnet workload install maui
- name: Restore dependencies
run: dotnet restore
- name: Build Android App
run: dotnet build -f net8.0-android -c Release
- name: Upload Android Artifacts
uses: actions/upload-artifact@v3
with:
name: android-artifacts
path: bin/Release/net8.0-android/**/*.apk
Bitrise Configuration for .NET MAUI
Configure your bitrise.yml
with:
# bitrise.yml snippet for .NET MAUI
workflows:
primary:
steps:
- activate-ssh-key@4: {}
- git-clone@6: {}
- nuget-restore@1: {}
- script@1:
inputs:
- content: |-
#!/bin/bash
dotnet workload install maui
dotnet build -f net8.0-android -c Release
- deploy-to-bitrise-io@2: {}
Azure DevOps Pipeline for .NET MAUI
Create an azure-pipelines.yml
file:
trigger:
- main
pool:
vmImage: "windows-latest"
variables:
buildConfiguration: "Release"
steps:
- task: UseDotNet@2
inputs:
packageType: "sdk"
version: "8.0.x"
includePreviewVersions: true
- script: dotnet workload install maui
displayName: "Install MAUI workload"
- task: DotNetCoreCLI@2
inputs:
command: "restore"
projects: "**/*.csproj"
feedsToUse: "select"
- task: DotNetCoreCLI@2
inputs:
command: "build"
projects: "**/*.csproj"
arguments: "-f net8.0-android -c $(buildConfiguration)"
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: "bin/$(buildConfiguration)/net8.0-android"
ArtifactName: "android-app"
publishLocation: "Container"
Best Practices for Mobile CI/CD
Regardless of the framework you're using, follow these best practices:
Code signing management: Use secure methods to manage certificates and profiles
- GitHub Actions: Use secrets for storing credentials
- Bitrise: Use the Code Signing tab
- Azure DevOps: Use secure files and variable groups
Environment-specific configurations: Separate dev, staging, and production builds
- Use environment variables or build variants
- Implement feature flags for controlled rollouts
Automated testing at multiple levels:
- Unit tests for business logic
- Integration tests for component interactions
- UI tests for critical user flows
Versioning strategy:
- Implement semantic versioning
- Automate version bumping based on commit messages or branch names
Distribution channels:
- Configure automated deployments to app stores
- Set up beta testing programs (TestFlight, Google Play Beta)
- Consider internal distribution for QA teams
Common Challenges and Solutions
Managing iOS Certificates and Provisioning Profiles
Challenge: iOS code signing is notoriously complex.
Solution:
- Use fastlane match with a private Git repository
- Implement Bitrise's iOS Code Signing feature
- Store certificates and profiles securely in Azure KeyVault
Handling Long Build Times
Challenge: Mobile CI/CD pipelines can be time-consuming.
Solution:
- Implement caching for dependencies
- Use incremental builds when possible
- Consider parallelizing platform-specific builds
Ensuring Consistent Environments
Challenge: Different CI environments can lead to inconsistent builds.
Solution:
- Use containerization (Docker) where possible
- Pin dependency versions strictly
- Document environment requirements thoroughly
Conclusion
Implementing CI/CD pipelines for Flutter, React Native, and .NET MAUI requires initial investment but pays significant dividends through improved quality, faster releases, and reduced manual effort. Each framework has its unique considerations, but the fundamental CI/CD principles remain consistent.
By following the implementation guides and best practices outlined in this article, you can create robust automation for your mobile app development workflow, regardless of which cross-platform technology you choose. Start small, focus on the most impactful automation first, and gradually expand your pipeline as your team gains confidence in the process.
Remember that CI/CD is not just about tooling but also about fostering a culture of quality and automation within your development team. Encourage developers to write tests, fix broken builds promptly, and continuously improve the pipeline itself.
Happy building!
Ready to streamline your internal app distribution?
Start sharing your app builds with your team and clients today.
No app store reviews, no waiting times.