HotCodePush
CI/CDProviders

Bitrise

Project Secrets that reach the store build's Xcode phase and Gradle task, and a Workflow on push to main that releases every merge to production.

To ship every commit from Bitrise, two project Secrets and two Workflows do the work. Every Step gets the Secrets, so the build step init added registers the tag's store build. A Workflow on push to main releases the over-the-air (OTA) update.

Ship every commit has the prerequisites and the three disciplines. This page carries the bitrise.yml of a Capacitor app and a table for the other frameworks.

Secrets to set

Both live under Workflow Editor › Secrets as project-level Secrets with "Expose for Pull Requests" off. Both reach every Workflow, since Bitrise has no Secret per Workflow. The key goes in as its base64 body on one line: grep -v -- '-----' hotcodepush-private-key.pem | tr -d '\n'.

SecretHolds
HOTCODEPUSH_TOKENHolds an API token from the console's API tokens page.
HOTCODEPUSH_SIGNING_KEYHolds the base64 body of the private key file signing-key create wrote, on one line. Leave it out until the app has a key.

The pipeline

One bitrise.yml, stored in the repository, holds both Workflows. The tools key pins Node.js 22, which the CLI needs (Supported versions), for every Workflow, since a stack's default differs.

bitrise.yml
format_version: "26"
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git

tools:
  nodejs: 22:installed

workflows:
  store-build:
    triggers:
      tag:
        - name: "v*"
    meta:
      bitrise.io:
        stack: osx-xcode-latest-stable
    steps:
      - git-clone@8: {}
      - npm@3:
          title: Install dependencies
          inputs:
            - command: ci
      - script@1:
          title: Build the web app and sync the native projects
          inputs:
            - content: npm run build && npx cap sync
      - set-java-version@1:
          inputs:
            - set_java_version: "21"
      - install-missing-android-tools@3:
          inputs:
            - gradlew_path: ./android/gradlew
      - android-build@1:
          inputs:
            - project_location: android
            - module: app
            - variant: release
            - build_type: aab
      - xcode-archive@6:
          inputs:
            - project_path: ios/App/App.xcodeproj
            - scheme: App
            - distribution_method: app-store
            - automatic_code_signing: api-key

  ota-update:
    triggers:
      push:
        - branch: main
    meta:
      bitrise.io:
        stack: ubuntu-latest-stable
    steps:
      - git-clone@8: {}
      - npm@3:
          title: Install dependencies
          inputs:
            - command: ci
      - npm@3:
          title: Build the web app
          inputs:
            - command: run build
      - script@1:
          title: Release to production
          inputs:
            - content: npx hotcodepush release create --channel production --bundle-version "$(git rev-parse --short HEAD)" --git-ref "$BITRISE_GIT_BRANCH" --yes --json

The store build

The tag trigger builds every v* tag on a macOS stack. The Step android-build runs the Gradle task of the release variant and xcode-archive the Xcode phase. Signing stays your own: the Apple service connection behind api-key, Android Sign after android-build.

Bitrise sets CI, so a store build without the token fails. The error catalog names the cause and binary the build step.

npx hotcodepush binary list names the first tag build with the bundle it ships.

By default, pull request builds get no Secrets. A Workflow that makes a store build on pull requests sets HOTCODEPUSH_OFFLINE: "1" under its envs. Such a build creates no binary (global options). A pull request dry run needs HOTCODEPUSH_TOKEN alone: switch "Expose for Pull Requests" on for the token and never for the key.

FrameworkStore build
React NativeDrop the web build Script and set-java-version. Add cocoapods-install@3 before xcode-archive, and point xcode-archive at ios/<App>.xcworkspace with scheme: <App>. Keep variant: release, since the wizard's default Debug creates no binary.
ExpoAdd a Script npx expo prebuild before the React Native Steps. The config plugin wires the build step at prebuild. Bitrise's Run EAS Build Step builds on EAS instead, with the token in the EAS environment. See the EAS Build recipe.
CapacitorUse the workflow as shown. set-java-version picks Java 21, which Capacitor compiles with, over the stacks' default 17. A CocoaPods project archives ios/App/App.xcworkspace after cocoapods-install@3 with podfile_path: ios/App/Podfile.
CordovaThe Script runs npm run build alone, and a hand-written www drops it. cordova-archive@3 with a release device build replaces the native Steps. A device build is an archive.

The OTA release

The push trigger runs the Workflow for a push to main and for nothing else, on a Linux stack.

  • A React Native or Expo app drops the build Step: the CLI packages the bundle per platform inside the upload. A Cordova app whose www is written by hand drops it too.
  • git-clone checks out the commit rather than the branch, so --git-ref "$BITRISE_GIT_BRANCH" records the branch. release lists every flag.

A failed release fails the Script Step with the CLI's exit code and prints the error as JSON, and the error catalog names the fix. A green build and a device that did not take the release is the other case. See Troubleshooting.

A preview channel per branch releases from a push trigger on that branch. Push builds get both Secrets, which a signed app's release needs. Test with preview channels has the commands. No build runs when a pull request closes, so give the channel an expiry.

What stays separate

Bitrise CodePush in Release Management stays unused: the app installs the HotCodePush SDK, not @bitrise/code-push-sdk. Its deployments, the codepush-publish Step and a BITRISE_API_TOKEN Secret play no part in the file above. An app leaving it follows From Bitrise CodePush. Bitrise builds the app and runs the HotCodePush CLI.

Next steps

  • Ship every commit names the three disciplines a pipeline that ships every commit keeps.
  • Test with preview channels builds the tester build that follows a preview channel from the QR code.
  • Roll out gradually puts --rollout-percent 10 --progression on the release line and explains the counters behind auto-pause.

Last updated on

On this page