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'.
| Secret | Holds |
|---|---|
HOTCODEPUSH_TOKEN | Holds an API token from the console's API tokens page. |
HOTCODEPUSH_SIGNING_KEY | Holds 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.
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 --jsonThe 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.
| Framework | Store build |
|---|---|
| React Native | Drop 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. |
| Expo | Add 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. |
| Capacitor | Use 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. |
| Cordova | The 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
wwwis written by hand drops it too. git-clonechecks 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 --progressionon the release line and explains the counters behind auto-pause.
Last updated on