Implementing CI/CD Pipelines
1. Setting Up GitHub Actions
Example: Basic GitHub Actions Workflow
name: React Native CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
- name: Build app
run: npm run build
| Step | Description | Notes |
|---|---|---|
| name | React Native CI |
Workflow name displayed in GitHub UI |
| on.push | branches: [ main ] |
Triggers workflow on push to main branch |
| on.pull_request | branches: [ main ] |
Triggers workflow on PR to main branch |
| jobs.build.runs-on | ubuntu-latest |
Runner environment for the job |
Note: Ensure
package.json has proper scripts for test and build.Warning: Avoid checking in secrets or sensitive data to the repository.
2. Configuring Fastlane
Example: Fastlane Configuration
lane :release do
ensure_git_branch 'main'
git_pull
increment_version_number
build_app
upload_to_app_store
end
| Fastlane Action | Description | Parameters |
|---|---|---|
| build_app | Builds the iOS app | workspace: "MyApp.xcworkspace" |
| upload_to_app_store | Uploads to App Store Connect | username: "developer@apple.com" |
| increment_version_number | Increments version number | version_number: "1.2.3" |
Note: Fastlane requires a
Gemfile to manage dependencies.
Warning: Ensure all credentials are securely stored using
fastlane’s built-in credential management or environment variables.
Fastlane Setup Steps
- Install Fastlane using
gem install fastlane - Run
fastlane initin your project root - Configure lanes in
Fastfile - Securely store credentials using
fastlane credentials
3. Using EAS Build
| Configuration Option | Description | Default Value | Notes |
|---|---|---|---|
| build.profile | Build profile to use from eas.json | production |
Must match a defined profile in eas.json |
| build.platform | Platform to build for | all |
Can be android, ios, or all |
| build.releaseChannel | Release channel to build from | default |
Used for over-the-air updates |
Note: EAS Build requires an Expo account and project setup.
Warning: EAS Build is only available for Expo projects.
Key Features of EAS Build
- Automated builds for iOS and Android
- Integration with Expo Application Services (EAS)
- Supports over-the-air updates
- Customizable build profiles
4. Implementing Automated Testing
Example: Setting up Jest for React Native
// package.json
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch"
},
"devDependencies": {
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0",
"@jest/globals": "^29.0.0"
}
}
| Test Type | Description | Tools | Notes |
|---|---|---|---|
| Unit Tests | Test individual functions or components in isolation | Jest, React Testing Library |
Use mocks for external dependencies |
| Integration Tests | Test interactions between components or modules | Jest, Detox |
Validate component behavior in context |
| End-to-End Tests | Test full user workflows in a real or simulated environment | Detox, Cypress |
Simulate real user interactions |
Workflow: Setting up Jest for React Native
- Install Jest and related dependencies
- Configure
jest.config.js - Create test files with
.test.jsextension - Run tests using
npm test
Comparison: Jest vs Detox for Testing
- Jest: Fast, great for unit and integration tests
- Detox: Slower, better for E2E testing
Note: Jest is the default testing framework for React Native. Detox is preferred for end-to-end tests.
5. Building iOS Apps in CI
| Step | Description | Command/Configuration |
|---|---|---|
| 1. Setup Xcode | Ensure the correct Xcode version is installed on the CI runner | xcode-select --install |
| 2. Install Dependencies | Install Node.js and npm packages | npm install |
| 3. Build iOS App | Use Xcode build command to compile the app | xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Release -sdk iphoneos |
| 4. Archive App | Create an archive for distribution | xcodebuild -exportArchive -archivePath MyApp.xcarchive -exportPath ./build |
Example: Fastlane Configuration
lane :build_ios do
# Install dependencies
cocoapods
# Build the app
xcodebuild(
workspace: "MyApp.xcworkspace",
scheme: "MyApp",
configuration: "Release",
sdk: "iphoneos"
)
# Archive the app
xcodebuild(
exportArchive: true,
archivePath: "MyApp.xcarchive",
exportPath: "./build"
)
end
Note: Ensure that CI runners have the required certificates and provisioning profiles for iOS builds.
6. Building Android Apps in CI
| Step | Description | Command/Config |
|---|---|---|
| 1. Setup Environment | Ensure Android SDK and build tools are installed | SDK_VERSION=30 |
| 2. Configure Gradle | Set up Gradle properties for CI | |
| 3. Build Command | Build the release APK | ./gradlew assembleRelease |
| 4. Sign APK | Sign the built APK with keystore | ./gradlew assembleRelease -Pandroid.signing.enabled=true |
Example: CI Pipeline Configuration
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup JDK
uses: actions/setup-java@v2
with:
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Build Release APK
run: |
./gradlew assembleRelease
ls -la app/build/outputs/apk/release/
Note: Ensure the keystore is securely stored in CI environment variables or secrets.
7. Managing Signing Credentials
| Credential Type | Description | Storage Method | Usage in CI/CD |
|---|---|---|---|
| Android Keystore | Keystore file for signing Android builds | Base64 encoded and stored as secret | Used by Gradle to sign APKs |
| iOS Distribution Certificate | Code signing certificate for iOS builds | Base64 encoded and stored as secret | Used by Xcode to sign IPA files |
| Provisioning Profile | File that grants permission to deploy iOS apps | Base64 encoded and stored as secret | Used by Xcode to deploy apps to devices |
Example: Storing Keystore in GitHub Secrets
base64 -i android-release-key.keystore -o keystore-base64.txt
secrets:
ANDROID_KEYSTORE: <base64_encoded_content>
Example: Using Keystore in Gradle
android {
signingConfigs {
release {
storeFile file("keystore.jks")
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias "my-key-alias"
keyPassword System.getenv("KEY_PASSWORD")
}
}
}
Example: Storing iOS Certificates in CircleCI
security create-keychain -p "keychain-pass" build.keychain
security import <certificate.p12> -k build.keychain -P "cert-pass"
security default-keychain -s build.keychain
Note: Ensure that signing credentials are never committed to version control. Use environment variables or CI/CD provider secrets management.
8. Implementing Code Signing
| Property | Description | Value |
|---|---|---|
| codeSigning | Enables code signing for Android and iOS builds | true |
| android.signingKey | Path to the Android signing key file | ./keystores/release-key.jks |
| ios.signingIdentity | Apple Developer signing identity | iPhone Distribution: Company Name (ABC123DEF456) |
Example: Code Signing Configuration in Gradle
android {
signingConfigs {
release {
storeFile file('keystores/release-key.jks')
storePassword 'release-key-password'
keyAlias 'release-key-alias'
keyPassword 'key-password'
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
Example: iOS Code Signing in Xcode
# Set signing identity in build settings
export CODE_SIGN_IDENTITY="iPhone Distribution: Company Name (ABC123DEF456)"
export PROVISIONING_PROFILE="Your-Provisioning-Profile"
Note: Code signing is required for publishing to app stores and must be configured securely in CI/CD pipelines.
9. Automating App Store Deployment
| Platform | Deployment Method | Configuration | Notes |
|---|---|---|---|
| iOS | fastlane |
Fastfile, Gymfile | Requires Apple Developer account and certificates |
| Android | Gradle |
build.gradle, signingConfig | Requires keystore file and credentials |
Example: Fastlane Configuration for iOS
lane :release do
match(type: "appstore")
gym(scheme: "MyApp", export_method: "app-store")
deliver(
force: true,
skip_screenshots: true,
skip_metadata: true
)
end
Example: Gradle Configuration for Android
android {
signingConfig signingConfigs.release
}
signingConfigs {
release {
storeFile file('my-release-key.keystore')
storePassword 'myStorePassword'
keyAlias 'myKeyAlias'
keyPassword 'myKeyPassword'
}
}
Note: Ensure that the deployment credentials are securely stored in CI/CD environment variables or secrets management tools.
10. Using Bitrise for Mobile CI
Example: Bitrise Workflow Configuration
workflows:
setup:
steps:
- activate-ssh-key@4.0.2:
inputs:
- ssh_key_path: $SSH_KEY_PATH
- git-clone@4.0.1:
inputs:
- clone_depth: 0
- git_url: $GIT_URL
- npm-install@1.0.0:
inputs:
- package_manager: yarn
build:
steps:
- xcode-build@1.0.0:
inputs:
- project_path: ./ios/MyApp.xcodeproj
- scheme: MyApp
- android-build@1.0.0:
inputs:
- gradle_task: assembleDebug
| Step | Description | Configuration |
|---|---|---|
| activate-ssh-key | Activates SSH key for secure repository access | ssh_key_path: $SSH_KEY_PATH |
| git-clone | Clones the repository with full history | clone_depth: 0 |
| npm-install | Installs dependencies using npm or yarn | package_manager: yarn |
| xcode-build | Builds iOS project using Xcode | project_path: ./ios/MyApp.xcodeproj |
| android-build | Builds Android project using Gradle | gradle_task: assembleDebug |
Note: Bitrise workflows are defined in YAML format and support plugins for various CI tasks.
Warning: Ensure sensitive data like SSH keys are stored securely in Bitrise's secret management.