mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-04 00:47:00 +01:00
Upstream mpv-android moved its build to NDK r30 (30.0.16248370), and each mpv-android revision pins its own NDK, so the two move together. The new revision also updates harfbuzz to 14.5.0, unibreak to 8.0, fribidi to 1.0.17, libxml2 to 2.15.4, fontconfig to 2.18.3 and curl to 8.22.0, and builds libass with assembly on x86_64 (nasm, already installed in CI). r30 brings an LLVM update with codegen and LTO fixes and sysroots up to API 37. It is also the NDK current SDK managers install, so a fresh setup no longer needs r29 installed beside it. The script change invalidates the cached libmpv tree, so CI rebuilds it once. The staged libraries are the same set as before, all 16 KiB aligned.
332 lines
13 KiB
YAML
332 lines
13 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: '30.0.16248370'
|
|
ANDROID_NDK_HOME: /usr/local/lib/android/sdk/ndk/30.0.16248370
|
|
|
|
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 nasm ninja-build pkg-config python3 unzip wget xz-utils yasm
|
|
# Not apt's meson: noble ships 1.3.2, and the fontconfig that the pinned
|
|
# mpv-android revision builds requires >= 1.11.
|
|
pipx install meson==1.12.1
|
|
|
|
- name: Install Android SDK and NDK
|
|
run: >-
|
|
sdkmanager
|
|
"platforms;android-${ANDROID_API}"
|
|
"build-tools;${ANDROID_BUILD_TOOLS}"
|
|
"ndk;${ANDROID_NDK}"
|
|
|
|
- id: toolchain
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: '1.96'
|
|
targets: aarch64-linux-android,x86_64-linux-android
|
|
|
|
# The registry and the installed helpers only. rust-cache reads
|
|
# `target/android/<triple>` as a profile directory and deletes the
|
|
# `release` tree under it before saving, so with its target caching on
|
|
# every run rebuilt both ABIs from scratch.
|
|
- uses: Swatinem/rust-cache@v2.9.1
|
|
with:
|
|
shared-key: android-registry
|
|
cache-targets: false
|
|
cache-on-failure: true
|
|
|
|
# The target directory as is: the host build the UniFFI bindings come
|
|
# from and both cargo-ndk ABIs. One entry for both jobs, since the signed
|
|
# build compiles the same crates for the same targets. A new lockfile
|
|
# starts from the last one's tree, so a version bump rebuilds only the
|
|
# workspace crates.
|
|
- id: target
|
|
uses: actions/cache/restore@v6
|
|
with:
|
|
path: target
|
|
key: rust-target-android-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: rust-target-android-${{ steps.toolchain.outputs.cachekey }}-
|
|
|
|
# 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. Built
|
|
# and saved in steps of its own, so a later failure in Gradle does not
|
|
# discard it the way a post-job cache save would.
|
|
- id: libmpv
|
|
uses: actions/cache/restore@v6
|
|
with:
|
|
path: android/app/build/generated/mpv
|
|
key: libmpv-${{ hashFiles('scripts/build-libmpv-android.sh') }}
|
|
|
|
- name: Build libmpv
|
|
run: bash scripts/build-libmpv-android.sh
|
|
|
|
- if: steps.libmpv.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v6
|
|
with:
|
|
path: android/app/build/generated/mpv
|
|
key: ${{ steps.libmpv.outputs.cache-primary-key }}
|
|
|
|
- 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
|
|
|
|
- if: steps.target.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v6
|
|
with:
|
|
path: target
|
|
key: ${{ steps.target.outputs.cache-primary-key }}
|
|
|
|
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 nasm ninja-build pkg-config python3 unzip wget xz-utils yasm
|
|
# Not apt's meson: noble ships 1.3.2, and the fontconfig that the pinned
|
|
# mpv-android revision builds requires >= 1.11.
|
|
pipx install meson==1.12.1
|
|
|
|
- name: Install Android SDK and NDK
|
|
run: >-
|
|
sdkmanager
|
|
"platforms;android-${ANDROID_API}"
|
|
"build-tools;${ANDROID_BUILD_TOOLS}"
|
|
"ndk;${ANDROID_NDK}"
|
|
|
|
- id: toolchain
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: '1.96'
|
|
targets: aarch64-linux-android,x86_64-linux-android
|
|
|
|
# The registry and the installed helpers only. rust-cache reads
|
|
# `target/android/<triple>` as a profile directory and deletes the
|
|
# `release` tree under it before saving, so with its target caching on
|
|
# every run rebuilt both ABIs from scratch.
|
|
- uses: Swatinem/rust-cache@v2.9.1
|
|
with:
|
|
shared-key: android-registry
|
|
cache-targets: false
|
|
cache-on-failure: true
|
|
|
|
# The target directory as is: the host build the UniFFI bindings come
|
|
# from and both cargo-ndk ABIs. One entry for both jobs, since the signed
|
|
# build compiles the same crates for the same targets. A new lockfile
|
|
# starts from the last one's tree, so a version bump rebuilds only the
|
|
# workspace crates.
|
|
- id: target
|
|
uses: actions/cache/restore@v6
|
|
with:
|
|
path: target
|
|
key: rust-target-android-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: rust-target-android-${{ steps.toolchain.outputs.cachekey }}-
|
|
|
|
# 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. Built
|
|
# and saved in steps of its own, so a later failure in Gradle does not
|
|
# discard it the way a post-job cache save would.
|
|
- id: libmpv
|
|
uses: actions/cache/restore@v6
|
|
with:
|
|
path: android/app/build/generated/mpv
|
|
key: libmpv-${{ hashFiles('scripts/build-libmpv-android.sh') }}
|
|
|
|
- name: Build libmpv
|
|
run: bash scripts/build-libmpv-android.sh
|
|
|
|
- if: steps.libmpv.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v6
|
|
with:
|
|
path: android/app/build/generated/mpv
|
|
key: ${{ steps.libmpv.outputs.cache-primary-key }}
|
|
|
|
- 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
|
|
|
|
- if: steps.target.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v6
|
|
with:
|
|
path: target
|
|
key: ${{ steps.target.outputs.cache-primary-key }}
|
|
|
|
# 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
|