Files
proton-stream/.github/workflows/android.yml
T
nvrlandClaude Opus 5.5 cf065fc5fe ci(android): install libdbus, cache cargo and the staged libmpv
Every Android run since August failed in :app:buildRustHost: the host
build of pstr-android reaches libdbus-sys through keyring's Secret
Service store, and the runner had no libdbus-1-dev. With no successful
run, nothing was ever cached, so each run rebuilt from nothing.

- libdbus-1-dev in both jobs
- one shared, save-on-failure Rust cache for both jobs
- the staged libmpv tree cached on the build script's hash; the script
  stamps its output with the revision and its own hash and skips the
  libmpv build when the stamp matches

PLAN.md records the Android parity and UI work that follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 03:06:53 +02:00

262 lines
9.6 KiB
YAML

name: Android
on:
push:
branches: [main]
# A `v*` tag reaches this workflow through release.yml, which calls it and
# publishes the signed APK. Triggering on the tag here as well would build
# the release twice.
workflow_call:
inputs:
signed_release:
required: false
default: false
type: boolean
pull_request:
paths:
- 'android/**'
- 'crates/pstr-android/**'
- 'crates/pstr-core/**'
- 'crates/pstr-meta/**'
- 'crates/pstr-stream/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'scripts/build-android.sh'
- 'scripts/build-libmpv-android.sh'
- '.github/workflows/android.yml'
workflow_dispatch:
inputs:
signed_release:
description: Build artifacts with the configured release key
required: false
default: false
type: boolean
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
ANDROID_API: '36'
ANDROID_BUILD_TOOLS: '37.0.0'
ANDROID_NDK: '29.0.14206865'
ANDROID_NDK_HOME: /usr/local/lib/android/sdk/ndk/29.0.14206865
jobs:
build:
name: Validate, debug, and unsigned release
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Enforce release versions and tag ancestry
shell: bash
run: |
workspace_version="$(awk '/^\[workspace.package\]/{found=1; next} found && /^\[/{exit} found && /^version = /{gsub(/[" ]/, "", $3); print $3; exit}' Cargo.toml)"
test -n "$workspace_version"
if [[ ! "$workspace_version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)([-+][0-9A-Za-z.-]+)?$ ]]; then
echo "::error::workspace version is not supported Android semver: $workspace_version"
exit 1
fi
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
test "$minor" -le 999
test "$patch" -le 999
expected_code=$((major * 1000000 + minor * 1000 + patch))
test "$expected_code" -ge 1
test "$expected_code" -le 2100000000
echo "EXPECTED_ANDROID_VERSION_NAME=$workspace_version" >> "$GITHUB_ENV"
echo "EXPECTED_ANDROID_VERSION_CODE=$expected_code" >> "$GITHUB_ENV"
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
tag="${GITHUB_REF_NAME#v}"
test "$tag" = "$workspace_version"
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
git merge-base --is-ancestor "$GITHUB_SHA" origin/main
fi
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
# The action's default `packages` includes `tools`, which cmdline-tools
# 16.0 no longer offers, so sdkmanager exits 1. The SDK pieces this
# build needs are installed explicitly below.
- uses: android-actions/setup-android@v3
with:
packages: platform-tools
log-accepted-android-sdk-licenses: false
- name: Install native build prerequisites
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
autoconf automake build-essential cmake curl git gperf libdbus-1-dev \
libtool meson nasm ninja-build pkg-config python3 unzip wget xz-utils \
yasm
- name: Install Android SDK and NDK
run: >-
sdkmanager
"platforms;android-${ANDROID_API}"
"build-tools;${ANDROID_BUILD_TOOLS}"
"ndk;${ANDROID_NDK}"
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: '1.96'
targets: aarch64-linux-android,x86_64-linux-android
# One cache for both jobs: the signed build compiles the same crates for
# the same targets. Saved on failure too, so a run that breaks late does
# not throw away everything it compiled before the break.
- uses: Swatinem/rust-cache@v2.9.1
with:
shared-key: android
cache-on-failure: true
# libmpv and its dependency tree are the slowest part of the build, and
# depend only on the pinned revision and the build script, which stamps
# its output with both and skips the build when the stamp matches.
- uses: actions/cache@v6
with:
path: android/app/build/generated/mpv
key: libmpv-${{ hashFiles('scripts/build-libmpv-android.sh') }}
- uses: gradle/actions/setup-gradle@v4
with:
gradle-version: '8.13'
- name: Validate Android version derivation and override
shell: bash
run: |
resolved="$(gradle --no-daemon -q -p android :app:printAndroidVersion)"
grep -Fx "versionName=$EXPECTED_ANDROID_VERSION_NAME" <<< "$resolved"
grep -Fx "versionCode=$EXPECTED_ANDROID_VERSION_CODE" <<< "$resolved"
if [[ "$EXPECTED_ANDROID_VERSION_CODE" -lt 2100000000 ]]; then
override_code=$((EXPECTED_ANDROID_VERSION_CODE + 1))
else
override_code=$((EXPECTED_ANDROID_VERSION_CODE - 1))
fi
overridden="$(ANDROID_VERSION_CODE="$override_code" gradle --no-daemon -q -p android :app:printAndroidVersion)"
grep -Fx "versionName=$EXPECTED_ANDROID_VERSION_NAME" <<< "$overridden"
grep -Fx "versionCode=$override_code" <<< "$overridden"
- name: Install native build helpers
run: |
cargo install cargo-ndk --version 4.1.2 --locked
cargo install uniffi --version 0.32.0 --features cli --locked
- name: Android checks and artifacts
run: bash scripts/build-android.sh all
signed-release:
name: Signed release
if: startsWith(github.ref, 'refs/tags/v') || inputs.signed_release
needs: build
runs-on: ubuntu-24.04
env:
ANDROID_RELEASE_STORE_PASSWORD: ${{ secrets.ANDROID_RELEASE_STORE_PASSWORD }}
ANDROID_RELEASE_KEY_ALIAS: ${{ secrets.ANDROID_RELEASE_KEY_ALIAS }}
ANDROID_RELEASE_KEY_PASSWORD: ${{ secrets.ANDROID_RELEASE_KEY_PASSWORD }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
# The action's default `packages` includes `tools`, which cmdline-tools
# 16.0 no longer offers, so sdkmanager exits 1. The SDK pieces this
# build needs are installed explicitly below.
- uses: android-actions/setup-android@v3
with:
packages: platform-tools
log-accepted-android-sdk-licenses: false
- name: Install native build prerequisites
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
autoconf automake build-essential cmake curl git gperf libdbus-1-dev \
libtool meson nasm ninja-build pkg-config python3 unzip wget xz-utils \
yasm
- name: Install Android SDK and NDK
run: >-
sdkmanager
"platforms;android-${ANDROID_API}"
"build-tools;${ANDROID_BUILD_TOOLS}"
"ndk;${ANDROID_NDK}"
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: '1.96'
targets: aarch64-linux-android,x86_64-linux-android
# One cache for both jobs: the signed build compiles the same crates for
# the same targets. Saved on failure too, so a run that breaks late does
# not throw away everything it compiled before the break.
- uses: Swatinem/rust-cache@v2.9.1
with:
shared-key: android
cache-on-failure: true
# libmpv and its dependency tree are the slowest part of the build, and
# depend only on the pinned revision and the build script, which stamps
# its output with both and skips the build when the stamp matches.
- uses: actions/cache@v6
with:
path: android/app/build/generated/mpv
key: libmpv-${{ hashFiles('scripts/build-libmpv-android.sh') }}
- uses: gradle/actions/setup-gradle@v4
with:
gradle-version: '8.13'
- name: Install native build helpers
run: |
cargo install cargo-ndk --version 4.1.2 --locked
cargo install uniffi --version 0.32.0 --features cli --locked
- name: Restore release keystore
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_BASE64 }}
run: |
test -n "$KEYSTORE_BASE64"
test -n "$ANDROID_RELEASE_STORE_PASSWORD"
test -n "$ANDROID_RELEASE_KEY_ALIAS"
test -n "$ANDROID_RELEASE_KEY_PASSWORD"
ANDROID_RELEASE_STORE_FILE="$RUNNER_TEMP/proton-stream-release.jks"
echo "ANDROID_RELEASE_STORE_FILE=$ANDROID_RELEASE_STORE_FILE" >> "$GITHUB_ENV"
printf '%s' "$KEYSTORE_BASE64" | base64 --decode > "$ANDROID_RELEASE_STORE_FILE"
- name: Build signed APK and AAB
run: bash scripts/build-android.sh signed
# The APK bundles a GPL libmpv, so its corresponding source ships next to
# it. The AAB is for Play only and stays out of the GitHub release.
- name: Stage release files
run: |
version="$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -n1)"
mkdir -p dist/android
cp android/app/build/outputs/apk/release/app-release.apk \
"dist/android/proton-stream-$version-android.apk"
cp android/app/build/generated/mpv/mpv-android-source-*.tar.gz dist/android/
- uses: actions/upload-artifact@v7
with:
name: android
path: dist/android/*
if-no-files-found: error
- uses: actions/upload-artifact@v7
with:
name: android-bundle
path: android/app/build/outputs/bundle/release/*.aab
if-no-files-found: error