Skip to content

Android Build and Release #10

Android Build and Release

Android Build and Release #10

name: Android Build and Release
on:
workflow_dispatch:
inputs: {}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
jobs:
build:
name: Build APKs and publish Release
runs-on: ubuntu-latest
env:
JAVA_HOME_21_X64: /usr/lib/jvm/java-21-openjdk-amd64
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper/
key: gradle-cache-${{ runner.os }}-v1
- name: Ensure Gradle wrapper version
run: |
./gradlew --version || true
# If you want to force wrapper update add a step to set distributionUrl in gradle/wrapper/gradle-wrapper.properties
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
- name: Build Debug APK
run: |
# Set JVM max heap via GRADLE_OPTS to avoid shell/PowerShell parsing issues with -Porg.gradle.jvmargs
GRADLE_OPTS="-Xmx3g" ./gradlew assembleDebug
- name: Decode keystore (if provided)
shell: bash
env:
RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
run: |
set -euo pipefail
if [ -n "${RELEASE_KEYSTORE_BASE64:-}" ]; then
mkdir -p app/release
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$PWD/app/release/release-keystore.jks"
ls -l "$PWD/app/release/release-keystore.jks"
else
echo "RELEASE_KEYSTORE_BASE64 not set; skipping keystore decode"
fi
- name: Build Release APK
env:
RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
RELEASE_KEYSTORE_KEY: ${{ secrets.RELEASE_KEYSTORE_KEY }}
RELEASE_KEYSTORE_SUBKEY: ${{ secrets.RELEASE_KEYSTORE_SUBKEY }}
run: |
set -euo pipefail
# Set JVM max heap via GRADLE_OPTS to avoid shell/PowerShell parsing issues with -Porg.gradle.jvmargs
GRADLE_OPTS="-Xmx3g"
# If keystore secret is present but file missing, decode it now (defensive)
if [ -n "${RELEASE_KEYSTORE_BASE64:-}" ] && [ ! -f "$PWD/app/release/release-keystore.jks" ]; then
mkdir -p app/release
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$PWD/app/release/release-keystore.jks"
chmod 600 "$PWD/app/release/release-keystore.jks"
fi
# Build with signing properties if keystore exists and passwords provided
STORE_FILE="$PWD/app/release/release-keystore.jks"
if [ -f "$STORE_FILE" ] && [ -n "${RELEASE_KEYSTORE_KEY:-}" ] && [ -n "${RELEASE_KEYSTORE_SUBKEY:-}" ]; then
echo "Keystore found — building signed release APK"
./gradlew assembleRelease -Pandroid.injected.signing.store.file="$STORE_FILE" -Pandroid.injected.signing.store.password="${RELEASE_KEYSTORE_KEY}" -Pandroid.injected.signing.key.password="${RELEASE_KEYSTORE_SUBKEY}" -Pandroid.injected.signing.key.alias=release
else
echo "No keystore/passwords provided — building release APK without injected signing properties"
./gradlew assembleRelease
fi
- name: Prepare artifacts
run: |
set -euo pipefail
mkdir -p release_artifacts
# Standard apk paths
DEBUG_APK=app/build/outputs/apk/debug/app-debug.apk
RELEASE_APK=app/build/outputs/apk/release/app-release.apk
COPIED=0
if [ -f "$DEBUG_APK" ]; then
cp "$DEBUG_APK" release_artifacts/app-debug.apk
COPIED=$((COPIED+1))
else
echo "Debug APK not found at $DEBUG_APK"
fi
if [ -f "$RELEASE_APK" ]; then
cp "$RELEASE_APK" release_artifacts/app-release.apk
COPIED=$((COPIED+1))
else
echo "Release APK not found at $RELEASE_APK"
fi
if [ $COPIED -ne 2 ]; then
echo "Missing apk. Listing outputs for debugging:"
ls -R app/build || true
fi
- name: Compute release metadata
id: meta
run: |
set -euo pipefail
# Derive version (Gradle file preferred, fallback to properties)
VERSION=""
if [ -f app/build.gradle ]; then
VERSION=$(grep -m1 "versionName" app/build.gradle | sed -E "s/.*versionName[[:space:]]+['\"]([^'\"]+)['\"].*/\1/" || true)
fi
if [ -z "$VERSION" ] && [ -f app/build.gradle.kts ]; then
VERSION=$(grep -m1 "versionName" app/build.gradle.kts | sed -E "s/.*versionName\\s*=?\\s*\"([^\"]+)\".*/\1/" || true)
fi
if [ -z "$VERSION" ] && [ -f gradle.properties ]; then
VERSION=$(grep -m1 -E "^(VERSION_NAME|versionName|VERSION)=" gradle.properties | cut -d'=' -f2- | tr -d '[:space:]' || true)
fi
VERSION=${VERSION:-"build-${GITHUB_RUN_ID}"}
COMMIT_ID=$(git rev-parse --short HEAD)
BODY=$(git log --pretty=format:"%h %ad - %s (%an)" --date=short --no-merges -n 200)
echo "tag_name=${COMMIT_ID}" >> "$GITHUB_OUTPUT"
echo "release_name=${VERSION}" >> "$GITHUB_OUTPUT"
{
echo 'body<<EOF'
echo "$BODY"
echo EOF
} >> "$GITHUB_OUTPUT"
- name: Create GitHub Release and upload APKs
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.meta.outputs.tag_name }}
name: ${{ steps.meta.outputs.release_name }}
body: ${{ steps.meta.outputs.body }}
fail_on_unmatched_files: false
files: |
release_artifacts/app-debug.apk
release_artifacts/app-release.apk