Skip to content

Build APKs

Build APKs #7

Workflow file for this run

name: Build APKs
# Manually triggerable from the Actions tab ("Run workflow"), and also runs automatically on
# pushes/PRs that touch the Android source, so regressions are caught early.
on:
workflow_dispatch:
push:
branches: [ main ]
paths:
- "source-code/**"
- ".github/workflows/build.yml"
pull_request:
branches: [ main ]
paths:
- "source-code/**"
- ".github/workflows/build.yml"
jobs:
build:
name: Build debug + release APKs
runs-on: ubuntu-latest
# Hard safety net: this job must never sit "waiting" indefinitely. If anything ever hangs
# again, the run fails loudly after 30 minutes instead of stalling silently.
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
# NOTE: intentionally NOT using a third-party "setup-android" action here.
# GitHub's ubuntu-latest runners already ship a fully installed, license-accepted Android
# SDK at $ANDROID_HOME/$ANDROID_SDK_ROOT. A separate SDK-setup action was previously used
# here and is what caused the workflow to hang "waiting" - it re-installs SDK components
# and can block on interactive license prompts. The Android Gradle Plugin can already
# auto-download any additional platform/build-tools it needs during the build itself,
# using the runner's pre-accepted licenses, so no extra action is required.
- name: Verify preinstalled Android SDK
run: |
echo "ANDROID_HOME=$ANDROID_HOME"
echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT"
ls "$ANDROID_HOME" || true
# Generate local.properties for this run instead of relying on one committed to the repo.
# (A hardcoded developer machine path in a committed local.properties previously shadowed
# the CI SDK entirely and broke every build - local.properties is now gitignored.)
- name: Write local.properties
working-directory: source-code
run: echo "sdk.dir=$ANDROID_HOME" > local.properties
- name: Grant execute permission for gradlew
working-directory: source-code
run: chmod +x ./gradlew
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('source-code/**/*.gradle*', 'source-code/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
gradle-${{ runner.os }}-
- name: Build debug APK
working-directory: source-code
run: ./gradlew assembleDebug --stacktrace --no-daemon
- name: Build release APK
working-directory: source-code
run: ./gradlew assembleRelease --stacktrace --no-daemon
- name: Collect APKs into outputs/
run: |
mkdir -p outputs
find source-code/app/build/outputs/apk/debug -name "*.apk" -exec cp {} outputs/ \;
find source-code/app/build/outputs/apk/release -name "*.apk" -exec cp {} outputs/ \;
ls -la outputs
- name: Read app version
id: version
run: |
VERSION=$(grep -m1 'versionName' source-code/app/build.gradle.kts | sed -E 's/.*"([^"]+)".*/\1/')
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Zip APKs
run: |
cd outputs
zip -r "HackerOS-App-v${{ steps.version.outputs.version }}-apks.zip" *.apk
rm -f *.apk
ls -la
- name: Upload outputs artifact
uses: actions/upload-artifact@v4
with:
name: outputs
path: outputs/*.zip
if-no-files-found: error