Skip to main content

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 init in your project root
  • Configure lanes in Fastfile
  • Securely store credentials using fastlane credentials

3. Using EAS Build

Example: Setting up EAS Build

npm install -g eas-cli
eas build:configure
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

  1. Install Jest and related dependencies
  2. Configure jest.config.js
  3. Create test files with .test.js extension
  4. 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
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m
org.gradle.configureondemand=true
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.

Bitrise CI Pipeline Overview

  • Uses YAML-based workflow definitions
  • Supports iOS and Android builds
  • Integrates with popular version control systems
  • Provides extensive plugin ecosystem for CI tasks

Was this article helpful?