Build a signed release APK in CI
The new android-release step signs with the keystore from the CI secrets ANDROID_KEYSTORE_BASE64 and ANDROID_KEYSTORE_PASSWORD. Without them, the step prints a warning and ends as a warning. The debug APK builds as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
M.hearthforge-ci.toml
@@ -100,6 +100,26 @@ cp app/build/outputs/apk/debug/app-debug.apk /ci/build/opentracker-debug.apk
"""
publish_file = ["/ci/build/opentracker-debug.apk"]
# Needs the CI secrets ANDROID_KEYSTORE_BASE64 (base64 of a PKCS12 keystore)
# and ANDROID_KEYSTORE_PASSWORD. Releases must keep the same key: Android
# refuses an update signed with another key.
[[steps]]
name = "android-release"
warn_on_fail = true
timeout = 1800
run_sh = """
if [ -z "${ANDROID_KEYSTORE_BASE64:-}" ] || [ -z "${ANDROID_KEYSTORE_PASSWORD:-}" ]; then
echo "WARNING: CI secrets ANDROID_KEYSTORE_BASE64 or ANDROID_KEYSTORE_PASSWORD missing. No signed release APK."
exit 1
fi
export ANDROID_KEYSTORE=/tmp/release.p12 ANDROID_KEY_ALIAS=opentracker
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > "$ANDROID_KEYSTORE"
cd project/android
./gradlew --no-daemon assembleRelease
cp app/build/outputs/apk/release/app-release.apk /ci/build/opentracker-release.apk
"""
publish_file = ["/ci/build/opentracker-release.apk"]
[[steps]]
name = "android-lint"
warn_on_fail = true
Mandroid/app/build.gradle.kts
@@ -16,6 +16,18 @@ android {
versionName = "0.1.0"
}
// Without ANDROID_KEYSTORE, assembleRelease builds an unsigned APK.
val keystore = providers.environmentVariable("ANDROID_KEYSTORE").orNull
val releaseSigning = keystore?.let {
signingConfigs.create("release") {
storeFile = file(it)
storePassword = providers.environmentVariable("ANDROID_KEYSTORE_PASSWORD").get()
keyAlias = providers.environmentVariable("ANDROID_KEY_ALIAS").get()
// PKCS12 has one password for the store and the key.
keyPassword = storePassword
}
}
buildTypes {
debug {
applicationIdSuffix = ".debug"
@@ -25,6 +37,7 @@ android {
release {
isMinifyEnabled = false
manifestPlaceholders["cleartext"] = "false"
signingConfig = releaseSigning
}
}