Builds / Remote builds
Signed store builds
Sign a release build and upload it to App Store Connect or Google Play
Revyl can sign your release build with your own certificate or keystore and
upload it to App Store Connect or Google Play. You add a signing step and a
deploy step to a build profile. Your xcodebuild or gradlew command does not
change.
--remote.iOS
Create an App Store Connect API key
- Open App Store Connect and go to Users and Access > Integrations > App Store Connect API.
- Click Generate API Key. Give it the App Manager role.
- Download the
.p8file. It can only be downloaded once. - Note the Key ID and the Issuer ID shown on the same page.
Export your distribution certificate
- Open Keychain Access on the Mac that holds the certificate.
- Under My Certificates, right-click the Apple Distribution certificate and click Export.
- Save it as a
.p12and set a password. Make sure the private key is included.
If any target in your project uses manual signing in Xcode, also download its App Store provisioning profile from the Apple Developer portal. Targets set to Automatically manage signing do not need one.
Add the credentials to Revyl
base64 -i distribution.p12 | revyl build secret set IOS_DIST_CERT --stdin
base64 -i AuthKey_ABC123.p8 | revyl build secret set ASC_API_KEY --stdin
revyl build secret set IOS_DIST_CERT_PASSWORD
# Only for manually signed targets
base64 -i App.mobileprovision | revyl build secret set IOS_APP_PROFILE --stdinAdd the steps to your build profile
Put ios-signing before your build commands and app-store-connect-deploy
after them. Use your own Key ID and Issuer ID.
build:
profiles:
release:
ios:
app_id: <your iOS app UUID>
setup_commands:
- yarn install --immutable
- npx --yes pod-install
build_commands:
- ios-signing:
certificate: IOS_DIST_CERT
certificate_password: IOS_DIST_CERT_PASSWORD
api_key: ASC_API_KEY
key_id: ABC123DEF4
issuer_id: 57246542-96fe-1a63-e053-0824d011072a
- xcodebuild archive -workspace ios/App.xcworkspace -scheme App -configuration Release -destination generic/platform=iOS -archivePath build/App.xcarchive $REVYL_XCODEBUILD_SIGNING_ARGS
- xcodebuild -exportArchive -archivePath build/App.xcarchive -exportOptionsPlist "$REVYL_EXPORT_OPTIONS" -exportPath build $REVYL_XCODEBUILD_SIGNING_ARGS
- app-store-connect-deploy:
api_key: ASC_API_KEY
key_id: ABC123DEF4
issuer_id: 57246542-96fe-1a63-e053-0824d011072a
output_path: build/App.ipaFor manually signed targets, add provisioning_profiles: [IOS_APP_PROFILE]
to ios-signing.
Run the build
Increase CFBundleVersion if you have already uploaded this build number,
then:
revyl build --profile release --platform ios --remoteThe build appears in TestFlight after Apple finishes processing it.
ios-signing inputs
| Input | Required | Description |
|---|---|---|
certificate | Yes | Secret name of the base64 .p12 |
certificate_password | No | Secret name of the .p12 password |
api_key, key_id, issuer_id | Yes, unless every target has a profile | Secret name of the .p8, plus the Key ID and Issuer ID as plain values |
provisioning_profiles | Only for manually signed targets | Secret names of base64 .mobileprovision files |
export_method | No | app-store-connect (default), ad-hoc, enterprise, or development |
export_options | No | Extra keys for ExportOptions.plist, for example uploadSymbols: false |
app-store-connect-deploy inputs
| Input | Required | Description |
|---|---|---|
api_key, key_id, issuer_id | Yes | Same values as above |
ipa | No | Path to the .ipa. Defaults to the profile's output_path |
apple_id | No | The app's numeric App Store ID |
Android
Get your upload keystore
Use the keystore you already sign releases with. Play Console shows its expected SHA-256 under Setup > App signing.
If you do not have one yet:
keytool -genkeypair -v -keystore upload.jks -alias upload -keyalg RSA -keysize 2048 -validity 10000Create a Google Play service account
- In Google Cloud Console, create a service account and download a JSON key for it.
- In Play Console, go to Users and permissions > Invite new users.
- Enter the service account's email address and give it release access to your app.
Add the credentials to Revyl
base64 -i upload.jks | revyl build secret set ANDROID_KEYSTORE --stdin
revyl build secret set GOOGLE_PLAY_SERVICE_ACCOUNT --stdin < service-account.json
revyl build secret set ANDROID_KEYSTORE_PASSWORDAdd the steps to your build profile
Put android-signing after your build command and google-play-deploy after
that. output_path must point to the one .aab or .apk your build produces.
build:
framework: android
profiles:
release:
android:
app_id: <your Android app UUID>
image: android-ubuntu-24.04-jdk-17-ndk-r27b
build_commands:
- ./gradlew --no-daemon :app:bundleRelease
- android-signing:
keystore: ANDROID_KEYSTORE
keystore_password: ANDROID_KEYSTORE_PASSWORD
- google-play-deploy:
service_account: GOOGLE_PLAY_SERVICE_ACCOUNT
package_name: com.example.app
track: internal
release_status: draft
output_path: app/build/outputs/bundle/release/app-release.aabandroid-signing signs the file at output_path in place, so nothing in your
Gradle config needs to change. If the keystore holds more than one key, add
key_alias.
Run the build
Increase versionCode if you have already uploaded this one, then:
revyl build --profile release --platform android --remoteWith release_status: draft the build is uploaded but not released. Release
it from Play Console, or set release_status: completed to release to the
track's testers straight away.
android-signing inputs
| Input | Required | Description |
|---|---|---|
keystore | Yes | Secret name of the base64 keystore |
keystore_password | Yes | Secret name of the keystore password |
key_alias | Only if the keystore has more than one key | Alias to sign with |
key_password | No | Secret name of the key password. Defaults to the keystore password |
google-play-deploy inputs
| Input | Required | Description |
|---|---|---|
service_account | Yes | Secret name of the service account JSON |
package_name | Yes | Application ID, for example com.example.app |
track | No | internal (default), alpha, beta, or production |
release_status | No | completed (default), draft, inProgress, or halted |
aab | No | Path to the .aab. Defaults to the profile's output_path |
mapping_file | No | Path to the R8 mapping file to upload with the build |
Troubleshooting
Credentials are checked before your build command runs, so a bad credential fails in seconds with the reason in the build log.
| Error | Fix |
|---|---|
| Certificate password rejected, or certificate has no private key | Re-export the .p12 from Keychain Access with the private key included |
| Profile does not match the certificate | Regenerate the profile for this certificate |
| Keystore password rejected, or alias not found | Check the values against your current release pipeline |
output_path must resolve to exactly one APK or AAB | Point output_path at the single file your build produces |
| Duplicate build number or version code | Bump it and run again |
| Google Play permission denied | Invite the service account to the app in Play Console |
Profiles with signing or deploy steps always build from source; cached build results are not reused.