mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-04 00:47:00 +01:00
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>
262 lines
9.6 KiB
YAML
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
|