Adding first APK build
This commit is contained in:
@@ -24,6 +24,29 @@ ARG SOUNDFONT_URL=http://rancid.kapsi.fi/windows.sf2
|
||||
# by anything else.
|
||||
ARG NODE_VERSION=20.18.1
|
||||
|
||||
# Android layer, for the Quest APK build (Quest 2, 3, 3S, Pro - all
|
||||
# arm64-v8a, see build-apk.sh). Same SDL2 major version as the desktop
|
||||
# build above, but SDL2/SDL2_mixer are much newer releases here - unlike
|
||||
# the desktop autotools build, Android needs their real CMake+NDK build
|
||||
# support, which only landed in later releases. targetSdkVersion 29 (not
|
||||
# compileSdk, which can and does stay newer) is deliberate: paired with
|
||||
# requestLegacyExternalStorage in the manifest, it keeps /sdcard a plain,
|
||||
# unrestricted shared folder instead of hitting Android 11+ scoped
|
||||
# storage - this is keyed off the *app's* targetSdkVersion, not the
|
||||
# device's own Android version, so it keeps working on newer Quest
|
||||
# hardware/OS updates too, not just whatever's current today.
|
||||
ARG ANDROID_SDL2_VERSION=2.28.5
|
||||
ARG ANDROID_SDL2_MIXER_VERSION=2.8.0
|
||||
ARG ANDROID_CMDLINE_TOOLS_VERSION=11076708
|
||||
ARG ANDROID_PLATFORM_VERSION=29
|
||||
# compileSdk in android/app/build.gradle - separate from the app's own
|
||||
# targetSdkVersion (29, above): compileSdk is just which android.jar the
|
||||
# app compiles against, and androidx.core needs a newer one than 29.
|
||||
ARG ANDROID_COMPILE_SDK_VERSION=34
|
||||
ARG ANDROID_BUILD_TOOLS_VERSION=34.0.0
|
||||
ARG ANDROID_NDK_VERSION=26.1.10909125
|
||||
ARG ANDROID_CMAKE_VERSION=3.22.1
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# build-essential/cmake/make: engine/ itself (CMake) and SDL2/SDL2_mixer
|
||||
@@ -41,11 +64,21 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
# libogg-dev/libvorbis-dev: SDL2_mixer's OGG Vorbis music decoder.
|
||||
# libasound2-dev: engine/CMakeLists.txt's optional native ALSA MIDI output.
|
||||
# openssh-client: the CI workflow's `sftp` publish step.
|
||||
# openjdk-17-jdk-headless: Gradle/AGP's own minimum JDK for the APK build.
|
||||
# unzip: extracts the Android cmdline-tools zip below.
|
||||
#
|
||||
# All apt installs deliberately live in this one RUN, first, so editing
|
||||
# anything below it (in particular the Android cross-compile steps, the
|
||||
# newest and least settled part of this file) never invalidates Docker's
|
||||
# build cache for this layer - and vice versa, adding a package here only
|
||||
# ever costs a rebuild of the (slow) layers below it, not a re-download
|
||||
# of packages that didn't change.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential cmake make git curl ca-certificates pkg-config gosu \
|
||||
libgl1-mesa-dev libglx-dev libxext-dev libx11-dev libxrandr-dev \
|
||||
libxi-dev libxfixes-dev libxss-dev libxinerama-dev libxcursor-dev \
|
||||
libogg-dev libvorbis-dev libasound2-dev openssh-client \
|
||||
openjdk-17-jdk-headless unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /opt/prebuilt
|
||||
@@ -95,6 +128,103 @@ RUN curl -sSL -o /tmp/node.tar.xz \
|
||||
&& tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1 \
|
||||
&& rm /tmp/node.tar.xz
|
||||
|
||||
# Android SDK/NDK: the cmdline-tools' own sdkmanager installs exactly the
|
||||
# platform/build-tools/NDK/CMake versions the app/build.gradle below pins.
|
||||
# gradlew (invoked by build-apk.sh) resolves its own pinned Gradle version
|
||||
# itself - no Gradle binary is baked into this image. Unlike the manually
|
||||
# cross-compiled SDL2/SDL2_mixer/fluidsynth-lite below, `./gradlew
|
||||
# assembleDebug` still needs network access at build time for Gradle/AGP's
|
||||
# own dependency resolution - an accepted, deliberate exception to this
|
||||
# image's otherwise-offline build philosophy (see build-apk.sh).
|
||||
ENV ANDROID_HOME=/opt/android-sdk \
|
||||
ANDROID_SDK_ROOT=/opt/android-sdk
|
||||
ENV PATH=${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}
|
||||
|
||||
RUN mkdir -p "${ANDROID_HOME}/cmdline-tools" \
|
||||
&& curl -sSL -o /tmp/cmdline-tools.zip \
|
||||
"https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS_VERSION}_latest.zip" \
|
||||
&& unzip -q /tmp/cmdline-tools.zip -d "${ANDROID_HOME}/cmdline-tools" \
|
||||
&& mv "${ANDROID_HOME}/cmdline-tools/cmdline-tools" "${ANDROID_HOME}/cmdline-tools/latest" \
|
||||
&& rm /tmp/cmdline-tools.zip \
|
||||
&& yes | sdkmanager --licenses >/dev/null \
|
||||
&& sdkmanager --install \
|
||||
"platform-tools" \
|
||||
"platforms;android-${ANDROID_PLATFORM_VERSION}" \
|
||||
"platforms;android-${ANDROID_COMPILE_SDK_VERSION}" \
|
||||
"build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
|
||||
"ndk;${ANDROID_NDK_VERSION}" \
|
||||
"cmake;${ANDROID_CMAKE_VERSION}"
|
||||
|
||||
ENV ANDROID_NDK_HOME=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}
|
||||
ENV ANDROID_NDK_TOOLCHAIN=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake
|
||||
|
||||
# SDL2, SDL2_mixer, and fluidsynth-lite, cross-compiled for arm64-v8a (the
|
||||
# Quest's only ABI, across Quest 2/3/3S/Pro) via the NDK's CMake toolchain file, each installed
|
||||
# to its own prefix under /opt/prebuilt/android/ - mirrors the desktop
|
||||
# build_ext/built_sdl / built_sdl_mixer layout, just for Android. Shipped
|
||||
# in the APK as separate .so's (see build-apk.sh), loaded in that order by
|
||||
# QuestShockActivity.getLibraries() before the game's own libmain.so.
|
||||
ARG ANDROID_ABI=arm64-v8a
|
||||
|
||||
RUN curl -sSLO "https://www.libsdl.org/release/SDL2-${ANDROID_SDL2_VERSION}.tar.gz" \
|
||||
&& tar xf "SDL2-${ANDROID_SDL2_VERSION}.tar.gz" \
|
||||
&& cmake -S "SDL2-${ANDROID_SDL2_VERSION}" -B build-sdl2-android \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_TOOLCHAIN}" \
|
||||
-DANDROID_ABI="${ANDROID_ABI}" -DANDROID_PLATFORM="android-${ANDROID_PLATFORM_VERSION}" \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/prebuilt/android/sdl2 -DBUILD_SHARED_LIBS=ON \
|
||||
-DSDL_STATIC=OFF \
|
||||
&& cmake --build build-sdl2-android -j"$(nproc)" \
|
||||
&& cmake --install build-sdl2-android \
|
||||
&& rm -rf "SDL2-${ANDROID_SDL2_VERSION}" "SDL2-${ANDROID_SDL2_VERSION}.tar.gz" build-sdl2-android
|
||||
|
||||
# All optional codecs disabled: Shockolate only ever calls
|
||||
# Mix_LoadWAV_RW/Mix_HookMusic (confirmed by grep - it feeds fluidsynth's
|
||||
# own PCM output through Mix_HookMusic, and never loads OGG/MOD/FLAC/MP3
|
||||
# game data), so plain WAVE support (always built in, no extra
|
||||
# dependency) is all that's needed - avoiding SDL2_mixer's vendored
|
||||
# third-party codec libraries entirely.
|
||||
RUN curl -sSLO "https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-${ANDROID_SDL2_MIXER_VERSION}.tar.gz" \
|
||||
&& tar xf "SDL2_mixer-${ANDROID_SDL2_MIXER_VERSION}.tar.gz" \
|
||||
&& cmake -S "SDL2_mixer-${ANDROID_SDL2_MIXER_VERSION}" -B build-sdl2mixer-android \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_TOOLCHAIN}" \
|
||||
-DANDROID_ABI="${ANDROID_ABI}" -DANDROID_PLATFORM="android-${ANDROID_PLATFORM_VERSION}" \
|
||||
-DCMAKE_PREFIX_PATH=/opt/prebuilt/android/sdl2 \
|
||||
-DCMAKE_FIND_ROOT_PATH=/opt/prebuilt/android/sdl2 \
|
||||
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \
|
||||
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \
|
||||
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/prebuilt/android/sdl2_mixer -DBUILD_SHARED_LIBS=ON \
|
||||
-DSDL2MIXER_VENDORED=OFF -DSDL2MIXER_SAMPLES=OFF -DSDL2MIXER_CMD=OFF \
|
||||
-DSDL2MIXER_FLAC=OFF -DSDL2MIXER_GME=OFF -DSDL2MIXER_MOD=OFF \
|
||||
-DSDL2MIXER_MP3=OFF -DSDL2MIXER_MIDI=OFF -DSDL2MIXER_OPUS=OFF -DSDL2MIXER_VORBIS=OFF \
|
||||
-DSDL2MIXER_WAVPACK=OFF \
|
||||
&& cmake --build build-sdl2mixer-android -j"$(nproc)" \
|
||||
&& cmake --install build-sdl2mixer-android \
|
||||
&& rm -rf "SDL2_mixer-${ANDROID_SDL2_MIXER_VERSION}" "SDL2_mixer-${ANDROID_SDL2_MIXER_VERSION}.tar.gz" build-sdl2mixer-android
|
||||
|
||||
RUN git clone https://github.com/EtherTyper/fluidsynth-lite.git fluidsynth-lite-android \
|
||||
&& cd fluidsynth-lite-android \
|
||||
&& git checkout "${FLUIDSYNTH_LITE_REF}" \
|
||||
&& sed -i 's/DLL"\ off/DLL"\ on/' CMakeLists.txt \
|
||||
&& sed -i 's/-Wall -Werror -std=gnu11/-Wall -std=gnu11/' CMakeLists.txt \
|
||||
&& sed -i 's/set ( LIBFLUID_LIBS m pthread )/set ( LIBFLUID_LIBS m )/' CMakeLists.txt \
|
||||
&& rm -rf .git \
|
||||
&& cd .. \
|
||||
&& cmake -S fluidsynth-lite-android -B build-fluidsynth-android \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_TOOLCHAIN}" \
|
||||
-DANDROID_ABI="${ANDROID_ABI}" -DANDROID_PLATFORM="android-${ANDROID_PLATFORM_VERSION}" \
|
||||
&& cmake --build build-fluidsynth-android -j"$(nproc)" \
|
||||
&& mkdir -p /opt/prebuilt/android/fluidsynth-lite/lib /opt/prebuilt/android/fluidsynth-lite/include \
|
||||
&& cp -a build-fluidsynth-android/src/libfluidsynth.so* /opt/prebuilt/android/fluidsynth-lite/lib/ \
|
||||
&& cp -a fluidsynth-lite-android/include/. /opt/prebuilt/android/fluidsynth-lite/include/ \
|
||||
# version.h is generated from version.h.in at configure time - fine on
|
||||
# the desktop build (in-source, so it lands right back in the source
|
||||
# tree), but this is an out-of-source build, so it only exists under
|
||||
# build-fluidsynth-android/ and must be copied in separately.
|
||||
&& cp -a build-fluidsynth-android/include/fluidsynth/version.h \
|
||||
/opt/prebuilt/android/fluidsynth-lite/include/fluidsynth/version.h \
|
||||
&& rm -rf fluidsynth-lite-android build-fluidsynth-android
|
||||
|
||||
COPY build-image/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||
COPY build-image/build-engine.sh /usr/local/bin/build-engine.sh
|
||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh /usr/local/bin/build-engine.sh
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1
|
||||
2
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds the Quest APK from a scratch, patched copy of engine/ (see
|
||||
# android/engine-patches/ - engine/ itself is never modified) plus the
|
||||
# Android SDL2/SDL2_mixer/fluidsynth-lite prebuilt into this image at
|
||||
# /opt/prebuilt/android/*. Run via ../run-image.sh (or directly, if
|
||||
# already inside this image - see the Makefile's `apk` target).
|
||||
#
|
||||
# Unlike build-engine.sh, this step needs network access: Gradle/AGP's
|
||||
# own dependency resolution isn't prebuilt into the image (see
|
||||
# build-image/Dockerfile's comment on that trade-off).
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(pwd)"
|
||||
ANDROID_DIR="$REPO_ROOT/android"
|
||||
SCRATCH_ENGINE="$REPO_ROOT/build/android-engine"
|
||||
|
||||
echo "== Preparing a scratch, patched copy of engine/ =="
|
||||
rm -rf "$SCRATCH_ENGINE"
|
||||
mkdir -p "$(dirname "$SCRATCH_ENGINE")"
|
||||
cp -a "$REPO_ROOT/engine" "$SCRATCH_ENGINE"
|
||||
for p in "$ANDROID_DIR"/engine-patches/*.patch; do
|
||||
patch -p1 -d "$SCRATCH_ENGINE" < "$p"
|
||||
done
|
||||
|
||||
echo "== Wiring up prebuilt Android SDL2_mixer/fluidsynth-lite (BUNDLED mode, like the desktop build) =="
|
||||
mkdir -p "$SCRATCH_ENGINE/build_ext/built_sdl_mixer" "$SCRATCH_ENGINE/build_ext/fluidsynth-lite"
|
||||
cp -a /opt/prebuilt/android/sdl2_mixer/. "$SCRATCH_ENGINE/build_ext/built_sdl_mixer/"
|
||||
mkdir -p "$SCRATCH_ENGINE/build_ext/fluidsynth-lite/src"
|
||||
cp -a /opt/prebuilt/android/fluidsynth-lite/lib/. "$SCRATCH_ENGINE/build_ext/fluidsynth-lite/src/"
|
||||
cp -a /opt/prebuilt/android/fluidsynth-lite/include/. "$SCRATCH_ENGINE/build_ext/fluidsynth-lite/include/"
|
||||
|
||||
echo "engineDir=$SCRATCH_ENGINE" > "$ANDROID_DIR/engine.properties"
|
||||
|
||||
echo "== Staging bundled assets (shaders, soundfont, get-assets text) =="
|
||||
ASSETS_DIR="$ANDROID_DIR/app/src/main/assets"
|
||||
rm -rf "$ASSETS_DIR"
|
||||
mkdir -p "$ASSETS_DIR/shaders" "$ASSETS_DIR/res"
|
||||
# GLES ports of engine/shaders/ (see android/gles-shaders/ and
|
||||
# android/engine-patches/04-android-opengl-es-render.patch) - not
|
||||
# engine/shaders/ itself, which is desktop-only GLSL.
|
||||
cp -a "$ANDROID_DIR/gles-shaders/." "$ASSETS_DIR/shaders/"
|
||||
cp "/opt/prebuilt/soundfont/default.sf2" "$ASSETS_DIR/res/soundfont.sf2"
|
||||
cp "$REPO_ROOT/res/assets/GET_ASSETS_QUEST.txt" "$ASSETS_DIR/GET_ASSETS_QUEST.txt"
|
||||
|
||||
echo "== Staging prebuilt Android SDL2/SDL2_mixer/fluidsynth-lite .so's into jniLibs =="
|
||||
JNI_LIBS_DIR="$ANDROID_DIR/app/src/main/jniLibs/arm64-v8a"
|
||||
rm -rf "$ANDROID_DIR/app/src/main/jniLibs"
|
||||
mkdir -p "$JNI_LIBS_DIR"
|
||||
find /opt/prebuilt/android/sdl2/lib /opt/prebuilt/android/sdl2_mixer/lib /opt/prebuilt/android/fluidsynth-lite/lib \
|
||||
-name '*.so' -exec cp -a {} "$JNI_LIBS_DIR/" \;
|
||||
|
||||
echo "== Building the APK (gradlew assembleDebug) =="
|
||||
cd "$ANDROID_DIR"
|
||||
./gradlew --no-daemon assembleDebug
|
||||
|
||||
APK="$ANDROID_DIR/app/build/outputs/apk/debug/app-debug.apk"
|
||||
[ -f "$APK" ] || { echo "BUILD FAIL: $APK not found after assembleDebug" >&2; exit 1; }
|
||||
|
||||
mkdir -p "$REPO_ROOT/dist"
|
||||
cp "$APK" "$REPO_ROOT/dist/questshock-debug.apk"
|
||||
|
||||
echo "== Done =="
|
||||
echo "APK: $REPO_ROOT/dist/questshock-debug.apk"
|
||||
Reference in New Issue
Block a user