diff --git a/.github/workflows/experimental.yml b/.github/workflows/experimental.yml index 6a3732c82..06a3d0e00 100644 --- a/.github/workflows/experimental.yml +++ b/.github/workflows/experimental.yml @@ -1,5 +1,5 @@ # Experimental builds, a rolling pre-release for experimental platforms: ones that aren't official but are available -# for testing (Linux aarch64, Windows on ARM, Android). From 1.0.0 they are never on the normal releases. Each build goes on the rolling pre-release "experimental", replacing that platform's previous file, +# for testing (Linux aarch64, Windows on ARM; Android was one until it joined the releases in Beta 6: release.yml). From 1.0.0 they are never on the normal releases. Each build goes on the rolling pre-release "experimental", replacing that platform's previous file, # or, for a reporter testing a fix, on a test build of its own. None of the files holds game code or game files. # Run by pushing a tag at the commit to build (from any branch that has this file): # experimental- -> the rolling "experimental" release; the pushed tag is deleted after the upload @@ -197,79 +197,10 @@ jobs: if-no-files-found: error compression-level: 0 - # the Android app (ci.yml's Android job) as a release build, signed with the published APKs' key (the repository's - # secrets ANDROID_KEYSTORE_B64 / ANDROID_KEYSTORE_PASSWORD: every build installs over the previous one) - android: - needs: check - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ needs.check.outputs.sha }} - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: '17' - - name: NDK and CMake - run: yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;30.0.16248370" "cmake;3.30.4" "platforms;android-36" > /dev/null - - name: Experimental version - env: - VERSION: ${{ needs.check.outputs.version }} - STAMP: ${{ needs.check.outputs.stamp }} - run: | - F=runtime/ui/launcher.mm - sed -i "s/^#define LARECOMP_VERSION \".*\"/#define LARECOMP_VERSION \"$VERSION\"/; s/^#define LARECOMP_EXPERIMENTAL_STAMP .*/#define LARECOMP_EXPERIMENTAL_STAMP ${STAMP}LL/" $F - grep -q "^#define LARECOMP_VERSION \"$VERSION\"" $F && grep -q "^#define LARECOMP_EXPERIMENTAL_STAMP ${STAMP}LL" $F || - { echo "::error::$F: LARECOMP_VERSION / LARECOMP_EXPERIMENTAL_STAMP not set"; exit 1; } - - name: Dependencies cache - id: deps - uses: actions/cache/restore@v4 - with: - path: android/deps/out - key: android-deps-${{ hashFiles('android/deps/build_deps.sh', 'android/deps/build_gen_deps.sh', 'android/gen/**') }} - - name: Dependencies (SDL3, shaderc, volk, Vulkan headers; the game code builder) - if: steps.deps.outputs.cache-hit != 'true' - run: | - bash android/deps/build_deps.sh - bash android/deps/build_gen_deps.sh - - uses: actions/cache/save@v4 - if: steps.deps.outputs.cache-hit != 'true' - with: - path: android/deps/out - key: ${{ steps.deps.outputs.cache-primary-key }} - - name: APK - env: - KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} - LARECOMP_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} - LARECOMP_VERSION_NAME: ${{ needs.check.outputs.version }} - STAMP: ${{ needs.check.outputs.stamp }} - run: | - [ -n "$KEYSTORE_B64" ] && [ -n "$LARECOMP_KEYSTORE_PASSWORD" ] || { echo "::error::the signing key secrets are not set"; exit 1; } - export LARECOMP_KEYSTORE=$RUNNER_TEMP/lasrecomp.keystore - echo "$KEYSTORE_B64" | base64 -d > "$LARECOMP_KEYSTORE" - # (Android's version code only grows: minutes since 2026-01-01) - export LARECOMP_VERSION_CODE=$(( ($(date -u -d "${STAMP:0:8} ${STAMP:8:2}:${STAMP:10:2}" +%s) - $(date -u -d 20260101 +%s)) / 60 )) - (cd android && ./gradlew assembleRelease --console=plain) - rm -f "$LARECOMP_KEYSTORE" - - name: Signed, and no game files - env: - VERSION: ${{ needs.check.outputs.version }} - run: | - APK=android/app/build/outputs/apk/release/app-release.apk - "$(ls -d "$ANDROID_HOME"/build-tools/* | sort -V | tail -1)/apksigner" verify --print-certs "$APK" - tools/check_apk.sh "$APK" - mkdir -p build/dist && cp "$APK" "build/dist/LAS Recomp-$VERSION-android.apk" && ls -la build/dist - - uses: actions/upload-artifact@v4 - with: - name: android - path: build/dist/*.apk - if-no-files-found: error - compression-level: 0 - publish: - needs: [check, linux, windows, android] + needs: [check, linux, windows] # (a platform whose build failed keeps its previous file; the others still go up) - if: always() && needs.check.result == 'success' && (needs.linux.result == 'success' || needs.windows.result == 'success' || needs.android.result == 'success') + if: always() && needs.check.result == 'success' && (needs.linux.result == 'success' || needs.windows.result == 'success') runs-on: ubuntu-24.04 permissions: contents: write # (only here: the experimental / test-arm release) @@ -301,7 +232,6 @@ jobs: "" \ "- Linux aarch64 (ARM): \`linux-aarch64.AppImage\`" \ "- Windows on ARM: \`windows-arm64.zip\` (Windows 11 on ARM, with a Vulkan 1.3 graphics driver)" \ - "- Android: \`android.apk\` ([requirements]($URL#system-requirements))" \ "" \ "## Help us make these better" \ "" \ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71327b9ab..40dd5e6c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,5 @@ # LAS Recomp's release builds: the macOS arm64 .dmg (make dmg), the Windows x64 .zip (make dist), the Linux -# x86_64 / aarch64 AppImages (make appimage) and the iOS kit .laskit (make ios-kit: the iOS app without game code +# x86_64 / aarch64 AppImages (make appimage), the signed Android .apk (from Beta 6) and the iOS kit .laskit (make ios-kit: the iOS app without game code # plus the tools any of those desktops completes it with), each from the same commit, put on a DRAFT # GitHub release with their sha256s. It never publishes: a person reads the draft, writes the notes and publishes # it. None of the files holds game code or game files (the start screen builds the game code from the player's own @@ -33,7 +33,7 @@ on: required: false default: '' platforms: - description: 'Test builds only: the platforms the fix targets (macos, windows, linux, linux-aarch64; comma list). Empty: all' + description: 'Test builds only: the platforms the fix targets (macos, windows, linux, linux-aarch64, android, ios; comma list). Empty: all' required: false default: '' permissions: @@ -84,10 +84,10 @@ jobs: fi # the platforms whose files ship: all for a release; a test build may name only the ones its fix targets PLATFORMS=${PLATFORMS//,/ } - if [ -z "${PLATFORMS// /}" ]; then PLATFORMS="macos windows linux linux-aarch64 ios" + if [ -z "${PLATFORMS// /}" ]; then PLATFORMS="macos windows linux linux-aarch64 android ios" elif [[ $TAG != test-* && $TAG != ci-test-* ]]; then echo "::error::platforms: only for test builds; a release ships all"; exit 1; fi for p in $PLATFORMS; do - case $p in macos|windows|linux|linux-aarch64|ios) ;; *) echo "::error::platform '$p': macos, windows, linux, linux-aarch64 or ios"; exit 1 ;; esac + case $p in macos|windows|linux|linux-aarch64|android|ios) ;; *) echo "::error::platform '$p': macos, windows, linux, linux-aarch64, android or ios"; exit 1 ;; esac done echo "platforms=$(echo $PLATFORMS)" >> "$GITHUB_OUTPUT" echo "sha=$SHA" >> "$GITHUB_OUTPUT" @@ -373,6 +373,67 @@ jobs: compression-level: 0 # (a release published on GitHub: a line on top of its notes while the files build) + # the Android app (as experimental.yml's android job) as a release build: this release's LARECOMP_VERSION, no + # experimental stamp (its update check takes the normal releases), signed with the published APKs' key (the + # repository's secrets ANDROID_KEYSTORE_B64 / ANDROID_KEYSTORE_PASSWORD: it installs over an experimental build) + android: + needs: check + if: needs.check.outputs.skip != 'true' + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.check.outputs.sha }} + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + - name: NDK and CMake + run: yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;30.0.16248370" "cmake;3.30.4" "platforms;android-36" > /dev/null + - name: Dependencies cache + id: deps + uses: actions/cache/restore@v4 + with: + path: android/deps/out + key: android-deps-${{ hashFiles('android/deps/build_deps.sh', 'android/deps/build_gen_deps.sh', 'android/gen/**') }} + - name: Dependencies (SDL3, shaderc, volk, Vulkan headers; the game code builder) + if: steps.deps.outputs.cache-hit != 'true' + run: | + bash android/deps/build_deps.sh + bash android/deps/build_gen_deps.sh + - uses: actions/cache/save@v4 + if: steps.deps.outputs.cache-hit != 'true' + with: + path: android/deps/out + key: ${{ steps.deps.outputs.cache-primary-key }} + - name: APK + env: + KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} + LARECOMP_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + LARECOMP_VERSION_NAME: ${{ needs.check.outputs.version }} + run: | + [ -n "$KEYSTORE_B64" ] && [ -n "$LARECOMP_KEYSTORE_PASSWORD" ] || { echo "::error::the signing key secrets are not set"; exit 1; } + export LARECOMP_KEYSTORE=$RUNNER_TEMP/lasrecomp.keystore + echo "$KEYSTORE_B64" | base64 -d > "$LARECOMP_KEYSTORE" + # (Android's version code only grows: minutes since 2026-01-01, as experimental.yml's) + export LARECOMP_VERSION_CODE=$(( ($(date -u +%s) - $(date -u -d 20260101 +%s)) / 60 )) + (cd android && ./gradlew assembleRelease --console=plain) + rm -f "$LARECOMP_KEYSTORE" + - name: Signed, and no game files + env: + VERSION: ${{ needs.check.outputs.version }} + run: | + APK=android/app/build/outputs/apk/release/app-release.apk + "$(ls -d "$ANDROID_HOME"/build-tools/* | sort -V | tail -1)/apksigner" verify --print-certs "$APK" + tools/check_apk.sh "$APK" + mkdir -p build/dist && cp "$APK" "build/dist/LAS Recomp-$VERSION-android.apk" && ls -la build/dist + - uses: actions/upload-artifact@v4 + with: + name: android + path: build/dist/*.apk + if-no-files-found: error + compression-level: 0 + announce: needs: check if: github.event_name == 'release' && needs.check.outputs.skip != 'true' @@ -391,7 +452,7 @@ jobs: gh release edit "$TAG" --notes-file new.md release: - needs: [check, macos, windows, linux, ios] + needs: [check, macos, windows, linux, android, ios] if: needs.check.outputs.skip != 'true' runs-on: ubuntu-24.04 permissions: @@ -412,11 +473,11 @@ jobs: run: | cd dist ls -la - [ "$(ls | wc -l)" = 5 ] || { echo "::error::expected 5 files"; exit 1; } + [ "$(ls | wc -l)" = 6 ] || { echo "::error::expected 6 files"; exit 1; } # (a test build: only the platforms its fix targets ship; the others were built as a compile check) for f in *; do case $f in *-macOS.dmg) p=macos ;; *-windows.zip) p=windows ;; *-linux-x86_64.AppImage) p=linux ;; - *-linux-aarch64.AppImage) p=linux-aarch64 ;; *-iOS.laskit) p=ios ;; + *-linux-aarch64.AppImage) p=linux-aarch64 ;; *-iOS.laskit) p=ios ;; *-android.apk) p=android ;; *) echo "::error::unknown file $f"; exit 1 ;; esac [[ " $PLATFORMS " == *" $p "* ]] || { echo "built, not shipped: $f"; rm "$f"; } done @@ -453,7 +514,7 @@ jobs: # (a release published on GitHub whose build failed: the "being built" line says so instead) failed: - needs: [check, macos, windows, linux, ios, release] + needs: [check, macos, windows, linux, android, ios, release] if: failure() && github.event_name == 'release' runs-on: ubuntu-24.04 permissions: diff --git a/README.md b/README.md index bf54d7c7f..03921db7a 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ native Windows, macOS, Linux, Android and iOS application. > - macOS - Apple Silicon only, Metal graphics backend + MetalFX > - Windows - x86-64 only, Vulkan graphics backend > - Linux - x86-64, Vulkan graphics backend (AppImage) -> - Android - arm64, Vulkan graphics backend - **experimental**: the latest APK is on the [Experimental builds](https://github.com/peiikai/LASRecomp/releases/tag/experimental) page +> - Android - arm64, Vulkan graphics backend > - iPhone and iPad - arm64, Metal graphics backend (sideloaded: see [iPhone and iPad](#iphone-and-ipad)) > - Linux aarch64 (ARM) - **experimental**: the latest build is on the [Experimental builds](https://github.com/peiikai/LASRecomp/releases/tag/experimental) page; reports welcome > ([docs/linux.md](docs/linux.md) lists what to include)