feat(android): T-AND-001 工程骨架(AGP 8.7.3 + Gradle 8.9 + Compose)

This commit is contained in:
2026-09-14 20:40:16 +08:00
parent 568664a9aa
commit 2f6212d5bf
21 changed files with 1091 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
#!/bin/bash
# ============================================================
# OpenDance Studio —— Android APK 打包(T-AND-009)
#
# 文档 §6.3 方式二:命令行 Gradle
#
# 前置:
# JAVA_HOME 指向 JDK 17(AGP 8.7 要求)
# ANDROID_HOME / ANDROID_SDK_ROOT 指向 Android SDK
# 需要 platforms;android-34 与 build-tools;34.0.0
#
# 用法:
# bash build/build-apk.sh # 同时产出 debug 与 release
# bash build/build-apk.sh debug
# bash build/build-apk.sh release
# ============================================================
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"
TARGET="${1:-all}"
case "$TARGET" in
debug|release|all) ;;
*) echo "用法:bash build/build-apk.sh [debug|release|all]" >&2; exit 2 ;;
esac
log() { printf '\033[1;34m[apk]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
# ---- 环境检查 ----
# 优先使用 JAVA_HOME 指定的 JDK:PATH 上的 java 可能是更新的版本,
# AGP 8.7 需要 17~21,检测时必须与 Gradle 实际使用的 JVM 一致。
JAVA_BIN="java"
if [ -n "${JAVA_HOME:-}" ] && [ -x "$JAVA_HOME/bin/java" ]; then
JAVA_BIN="$JAVA_HOME/bin/java"
fi
command -v "$JAVA_BIN" >/dev/null 2>&1 || die "未找到 java,请安装 JDK 17 或设置 JAVA_HOME"
JAVA_MAJOR="$("$JAVA_BIN" -version 2>&1 | head -1 | sed -E 's/.*version "([0-9]+).*/\1/')"
log "Java:$JAVA_BIN (主版本 $JAVA_MAJOR,AGP 8.7 需要 17+)"
if [ "$JAVA_MAJOR" -lt 17 ] 2>/dev/null; then
die "JDK 版本过低:需要 17 或更高(当前 $JAVA_MAJOR)"
fi
SDK="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
if [ -z "$SDK" ]; then
for candidate in "$HOME/Android/Sdk" /opt/android-sdk /usr/lib/android-sdk; do
[ -d "$candidate" ] && SDK="$candidate" && break
done
fi
[ -n "$SDK" ] && [ -d "$SDK" ] || die "未找到 Android SDK,请设置 ANDROID_HOME"
log "Android SDK:$SDK"
if [ ! -f "$PROJECT_DIR/local.properties" ]; then
echo "sdk.dir=$SDK" > "$PROJECT_DIR/local.properties"
log "已写入 local.properties"
fi
[ -f "$PROJECT_DIR/gradlew" ] || die "缺少 gradlew(请先执行 gradle wrapper)"
# ---- 签名检查 ----
if [ "$TARGET" != "debug" ]; then
if [ -f "$PROJECT_DIR/keystore.properties" ]; then
log "使用 keystore.properties 中的发布签名"
else
log "提示:未找到 keystore.properties,release 将回退为 debug 签名"
log " 正式发布请先执行:bash build/gen-keystore.sh"
fi
fi
# ---- 构建 ----
if [ "$TARGET" = "debug" ] || [ "$TARGET" = "all" ]; then
log "构建 debug APK…"
./gradlew assembleDebug --console=plain
fi
if [ "$TARGET" = "release" ] || [ "$TARGET" = "all" ]; then
log "构建 release APK…"
./gradlew assembleRelease --console=plain
fi
# ---- 校验产物 ----
DEBUG_APK="app/build/outputs/apk/debug/app-debug.apk"
RELEASE_APK="app/build/outputs/apk/release/app-release.apk"
verify_apk() {
local apk="$1"
local label="$2"
[ -f "$apk" ] || { echo " ✗ 未生成 $label:$apk"; return 1; }
local size
size=$(stat -c%s "$apk")
# APK 是 zip,校验魔数 PK
local magic
magic=$(head -c 2 "$apk" | od -An -tx1 | tr -d ' \n')
[ "$magic" = "504b" ] || { echo " ✗ $label 不是合法 APK(魔数 $magic)"; return 1; }
# 校验是否已签名:APK v2 签名块附近含 "APK Sig Block 42"
local signed="未检出 v2 签名块"
if grep -qa "APK Sig Block 42" "$apk"; then
signed="已签名(APK Signature Scheme v2)"
elif unzip -l "$apk" 2>/dev/null | grep -q "META-INF/.*\.RSA"; then
signed="已签名(v1 JAR 签名)"
fi
echo " ✓ $label:$apk"
echo " 大小 $((size / 1024)) KiB | $signed"
return 0
}
echo ""
log "产物校验:"
FAILED=0
if [ "$TARGET" = "debug" ] || [ "$TARGET" = "all" ]; then
verify_apk "$DEBUG_APK" "Debug APK" || FAILED=1
fi
if [ "$TARGET" = "release" ] || [ "$TARGET" = "all" ]; then
verify_apk "$RELEASE_APK" "Release APK" || FAILED=1
fi
[ "$FAILED" -eq 0 ] || die "有产物未通过校验"
echo ""
log "安装到已连接设备:"
echo " adb install -r $DEBUG_APK"
echo " adb install -r $RELEASE_APK"
echo ""
log "查看签名信息:"
echo " \$ANDROID_HOME/build-tools/34.0.0/apksigner verify --print-certs $RELEASE_APK"