gmod-rs/android/build.sh
Niko Marmeladkov e07f39d8dc Android: логи в logcat и сборка под произвольный ABI
tracing на Android пишет в logcat (adb logcat -s gmod-rs), иначе диагностика
запуска на устройстве теряется. build.sh принимает ANDROID_ABI (arm64-v8a,
x86_64, armeabi-v7a, x86) — x86_64 нужен для проверки в эмуляторе.
2026-10-23 13:41:43 +03:00

145 lines
5.5 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Сборка debug-APK клиента gmod-rs под Android (arm64-v8a).
#
# Без Gradle: SDK/NDK + cargo + aapt2/d8/apksigner. Так проще в окружении без
# скачивания Android Gradle Plugin, а результатом всё равно является обычный
# подписанный APK.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ANDROID_DIR="$ROOT/android"
BUILD="$ANDROID_DIR/build"
OUT_DIR="$ROOT/target/android"
API=31
ABI="${ANDROID_ABI:-arm64-v8a}"
case "$ABI" in
arm64-v8a) TARGET=aarch64-linux-android; CLANG_PREFIX=aarch64-linux-android ;;
x86_64) TARGET=x86_64-linux-android; CLANG_PREFIX=x86_64-linux-android ;;
armeabi-v7a) TARGET=armv7-linux-androideabi; CLANG_PREFIX=armv7a-linux-androideabi ;;
x86) TARGET=i686-linux-android; CLANG_PREFIX=i686-linux-android ;;
*) echo "неизвестный ABI: $ABI" >&2; exit 1 ;;
esac
if [[ "$ABI" == "arm64-v8a" ]]; then
OUT="$OUT_DIR/gmod-rs-debug.apk"
else
OUT="$OUT_DIR/gmod-rs-debug-$ABI.apk"
fi
SDK="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
if [[ -z "$SDK" || ! -d "$SDK" ]]; then
for candidate in "$HOME/Android/Sdk" /opt/android-sdk; do
if [[ -d "$candidate" ]]; then SDK="$candidate"; break; fi
done
fi
if [[ -z "$SDK" || ! -d "$SDK" ]]; then
echo "не найден Android SDK (задайте ANDROID_HOME)" >&2
exit 1
fi
NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK:-}}"
if [[ -z "$NDK" || ! -d "$NDK" ]]; then
NDK="$(find "$SDK/ndk" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort -V | tail -1 || true)"
fi
if [[ -z "$NDK" || ! -d "$NDK" ]]; then
NDK=/opt/android-ndk
fi
if [[ ! -f "$NDK/build/cmake/android.toolchain.cmake" ]]; then
echo "не найден Android NDK (задайте ANDROID_NDK_HOME)" >&2
exit 1
fi
BUILD_TOOLS="$(find "$SDK/build-tools" -maxdepth 1 -mindepth 1 -type d | sort -V | tail -1)"
PLATFORM_DIR="$(find "$SDK/platforms" -maxdepth 1 -mindepth 1 -type d | sort -V | tail -1)"
ANDROID_JAR="$PLATFORM_DIR/android.jar"
if [[ ! -f "$ANDROID_JAR" ]]; then
echo "не найден android.jar в $PLATFORM_DIR" >&2
exit 1
fi
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
CC_BIN="$TOOLCHAIN/${CLANG_PREFIX}${API}-clang"
if [[ ! -x "$CC_BIN" ]]; then
CC_BIN="$TOOLCHAIN/${CLANG_PREFIX}-clang"
fi
if [[ ! -x "$CC_BIN" ]]; then
echo "не найден clang NDK для $TARGET в $TOOLCHAIN" >&2
exit 1
fi
# --- нативная часть -------------------------------------------------------
export ANDROID_NDK="$NDK"
export CMAKE_TOOLCHAIN_FILE="$NDK/build/cmake/android.toolchain.cmake"
export ANDROID_PLATFORM="android-$API"
TARGET_U="${TARGET//-/_}"
export "CC_${TARGET_U}=$CC_BIN"
export "AR_${TARGET_U}=$TOOLCHAIN/llvm-ar"
export "RANLIB_${TARGET_U}=$TOOLCHAIN/llvm-ranlib"
LINKER_VAR="CARGO_TARGET_$(echo "$TARGET_U" | tr '[:lower:]' '[:upper:]')_LINKER"
export "$LINKER_VAR=$CC_BIN"
echo "== cargo build ($TARGET / $ABI, release)"
(cd "$ROOT" && cargo build --release -p client --lib --target "$TARGET")
LIB_DIR="$ROOT/target/$TARGET/release"
SDL_SO="$LIB_DIR/libSDL3.so"
CLIENT_SO="$LIB_DIR/libclient.so"
if [[ ! -f "$SDL_SO" ]]; then
# sdl3-sys кладёт собранную SDL3 в каталог сборки, если не смог
# скопировать её наверх.
SDL_SO="$(find "$ROOT/target/$TARGET/release/build" -path '*/out/lib/libSDL3.so' | head -1)"
fi
if [[ ! -f "$SDL_SO" || ! -f "$CLIENT_SO" ]]; then
echo "не найдены собранные libSDL3.so/libclient.so" >&2
exit 1
fi
# --- Java + пакет ---------------------------------------------------------
rm -rf "$BUILD"
mkdir -p "$BUILD/classes" "$BUILD/dex" "$BUILD/lib/$ABI" "$OUT_DIR"
echo "== javac"
find "$ANDROID_DIR/app/src/main/java" -name '*.java' > "$BUILD/sources.txt"
javac --release 11 -Xlint:-options -cp "$ANDROID_JAR" -d "$BUILD/classes" @"$BUILD/sources.txt"
echo "== d8"
find "$BUILD/classes" -name '*.class' > "$BUILD/classes.txt"
"$BUILD_TOOLS/d8" --release --lib "$ANDROID_JAR" --min-api "$API" \
--output "$BUILD/dex" @"$BUILD/classes.txt"
echo "== aapt2 link"
"$BUILD_TOOLS/aapt2" link -o "$BUILD/unsigned.apk" \
--manifest "$ANDROID_DIR/AndroidManifest.xml" \
-I "$ANDROID_JAR"
cp "$SDL_SO" "$BUILD/lib/$ABI/libSDL3.so"
# SDLActivity грузит «main»: имя файла обязано быть libmain.so, а не
# libclient.so (внутри — наш cdylib с экспортом SDL_main).
cp "$CLIENT_SO" "$BUILD/lib/$ABI/libmain.so"
"$TOOLCHAIN/llvm-strip" --strip-debug "$BUILD/lib/$ABI/libSDL3.so" 2>/dev/null || true
"$TOOLCHAIN/llvm-strip" --strip-debug "$BUILD/lib/$ABI/libmain.so" 2>/dev/null || true
(cd "$BUILD/dex" && zip -q "$BUILD/unsigned.apk" classes.dex)
(cd "$BUILD" && zip -q -r "$BUILD/unsigned.apk" "lib")
echo "== zipalign"
"$BUILD_TOOLS/zipalign" -f 4 "$BUILD/unsigned.apk" "$BUILD/aligned.apk"
KEYSTORE="$ANDROID_DIR/debug.keystore"
if [[ ! -f "$KEYSTORE" ]]; then
echo "== debug keystore"
keytool -genkeypair -v -keystore "$KEYSTORE" \
-storepass android -keypass android \
-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 \
-dname "CN=Android Debug,O=Android,C=US" >/dev/null
fi
echo "== apksigner"
"$BUILD_TOOLS/apksigner" sign \
--ks "$KEYSTORE" --ks-pass pass:android --key-pass pass:android \
--ks-key-alias androiddebugkey \
--out "$OUT" "$BUILD/aligned.apk"
"$BUILD_TOOLS/apksigner" verify --verbose "$OUT"
echo
echo "APK: $OUT"
echo "install: adb install -r \"$OUT\""