- 移除 update-alternatives(对 SDKMAN! 无效) - 纯 JAVA_HOME 方案:安装 JDK 17 到 /usr/lib/jvm,设置 JAVA_HOME - 构建前用 /bin/java -version 硬性验证 - Gradle 通过 -Dorg.gradle.java.home 强制使用 JDK 17 - PATH 首位放 /bin 确保 gradlew 找到正确 JDK
277 lines
9.3 KiB
Bash
Executable File
277 lines
9.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
#
|
||
# build.codespace.sh — 在 GitHub Codespaces 中构建 AirDisplay APK
|
||
#
|
||
# 用法:
|
||
# chmod +x build.codespace.sh && ./build.codespace.sh
|
||
#
|
||
# 原理:
|
||
# GitHub Codespaces 通过 SDKMAN! 管理默认 JDK(当前为 JDK 25)。
|
||
# Android Gradle Plugin 8.2.2 不支持 JDK > 21,因此需要 JDK 17。
|
||
# 脚本不做 update-alternatives(对 SDKMAN! 无效),而是直接安装 JDK 17、
|
||
# 设置 JAVA_HOME 指向它,并通过 -Dorg.gradle.java.home= 强递给 Gradle。
|
||
#
|
||
# 环境变量(可选):
|
||
# ANDROID_SDK_ROOT — SDK 安装路径,默认 $HOME/android-sdk
|
||
# BUILD_TYPE — debug 或 release,默认 debug
|
||
#
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 颜色
|
||
# ──────────────────────────────────────────────
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
|
||
log() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||
err() { echo -e "${RED}[✗]${NC} $1"; }
|
||
info() { echo -e "${CYAN}[i]${NC} $1"; }
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 配置
|
||
# ──────────────────────────────────────────────
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_DIR="$SCRIPT_DIR"
|
||
|
||
ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$HOME/android-sdk}"
|
||
BUILD_TYPE="${BUILD_TYPE:-debug}"
|
||
CMDLINE_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
|
||
SDK_MANAGER="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager"
|
||
|
||
SDK_COMPONENTS=(
|
||
"platforms;android-34"
|
||
"build-tools;34.0.0"
|
||
"platform-tools"
|
||
)
|
||
|
||
# 运行中会填充
|
||
JAVA17_HOME=""
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 阶段 1:找到或安装 JDK 17
|
||
# ──────────────────────────────────────────────
|
||
install_jdk() {
|
||
info "查找/安装 JDK 17 ..."
|
||
|
||
# 扫描 apt 安装的标准路径
|
||
local found=""
|
||
for dir in /usr/lib/jvm/java-17-openjdk-*; do
|
||
if [ -d "$dir" ] && [ -x "$dir/bin/java" ]; then
|
||
found="$dir"
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ -n "$found" ]; then
|
||
JAVA17_HOME="$found"
|
||
log "JDK 17 已安装: $JAVA17_HOME"
|
||
return
|
||
fi
|
||
|
||
# 还没装,用 apt 装
|
||
warn "安装 openjdk-17-jdk-headless ..."
|
||
sudo apt-get update -qq
|
||
sudo apt-get install -y -qq openjdk-17-jdk-headless
|
||
|
||
# 装完再扫一次
|
||
for dir in /usr/lib/jvm/java-17-openjdk-*; do
|
||
if [ -d "$dir" ] && [ -x "$dir/bin/java" ]; then
|
||
JAVA17_HOME="$dir"
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ -z "$JAVA17_HOME" ]; then
|
||
err "JDK 17 安装失败,未在 /usr/lib/jvm/ 下找到"
|
||
err "手动安装: sudo apt-get install openjdk-17-jdk-headless"
|
||
exit 1
|
||
fi
|
||
|
||
log "JDK 17 安装完成: $JAVA17_HOME"
|
||
}
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 阶段 2:安装 Android SDK
|
||
# ──────────────────────────────────────────────
|
||
install_sdk() {
|
||
info "检查 Android SDK ..."
|
||
|
||
if [ -x "$SDK_MANAGER" ]; then
|
||
log "命令行工具已安装"
|
||
else
|
||
warn "下载 Android 命令行工具 ..."
|
||
mkdir -p "$ANDROID_SDK_ROOT"
|
||
cd "$ANDROID_SDK_ROOT"
|
||
curl -fsSL "$CMDLINE_TOOLS_URL" -o cmdline-tools.zip
|
||
unzip -q cmdline-tools.zip
|
||
rm -f cmdline-tools.zip
|
||
|
||
mkdir -p cmdline-tools/latest
|
||
if [ -d cmdline-tools/bin ]; then
|
||
mv cmdline-tools/bin cmdline-tools/latest/
|
||
mv cmdline-tools/lib cmdline-tools/latest/
|
||
mv cmdline-tools/NOTICE.txt cmdline-tools/latest/ 2>/dev/null || true
|
||
mv cmdline-tools/source.properties cmdline-tools/latest/ 2>/dev/null || true
|
||
fi
|
||
log "命令行工具已安装"
|
||
fi
|
||
|
||
info "接受 SDK licenses ..."
|
||
yes | "$SDK_MANAGER" --licenses 2>&1 | tail -1 || true
|
||
|
||
info "安装 SDK 组件(首次需 1-2 分钟)..."
|
||
for comp in "${SDK_COMPONENTS[@]}"; do
|
||
local dir_path="${comp/;/\/}"
|
||
if [ -d "$ANDROID_SDK_ROOT/$dir_path" ]; then
|
||
log " 已安装: $comp"
|
||
continue
|
||
fi
|
||
info " 安装: $comp ..."
|
||
yes | "$SDK_MANAGER" "$comp" 2>&1 | tail -1 || true
|
||
done
|
||
|
||
log "Android SDK 就绪"
|
||
}
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 阶段 3:local.properties
|
||
# ──────────────────────────────────────────────
|
||
setup_local_properties() {
|
||
info "配置 local.properties ..."
|
||
local props="$PROJECT_DIR/local.properties"
|
||
if [ -f "$props" ] && grep -q "sdk.dir" "$props" 2>/dev/null; then
|
||
log "已存在"
|
||
return
|
||
fi
|
||
rm -f "$props"
|
||
{
|
||
echo "# Auto-generated by build.codespace.sh"
|
||
echo "# $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||
echo "sdk.dir=$ANDROID_SDK_ROOT"
|
||
echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m"
|
||
} > "$props"
|
||
log "已生成"
|
||
}
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 阶段 4:Gradle Wrapper
|
||
# ──────────────────────────────────────────────
|
||
setup_gradle_wrapper() {
|
||
if [ -x "$PROJECT_DIR/gradlew" ]; then
|
||
log "Gradle Wrapper 已存在"
|
||
return
|
||
fi
|
||
info "生成 Gradle Wrapper (v8.5) ..."
|
||
if ! command -v gradle &>/dev/null; then
|
||
sudo apt-get install -y -qq gradle > /dev/null 2>&1
|
||
fi
|
||
cd "$PROJECT_DIR"
|
||
gradle wrapper --gradle-version 8.5 > /dev/null 2>&1
|
||
chmod +x gradlew
|
||
log "完成"
|
||
}
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 阶段 5:构建 APK
|
||
# ──────────────────────────────────────────────
|
||
build_apk() {
|
||
# ---- 验证 JAVA_HOME ----
|
||
if [ -z "$JAVA17_HOME" ] || [ ! -x "$JAVA17_HOME/bin/java" ]; then
|
||
err "JAVA17_HOME 无效: $JAVA17_HOME"
|
||
exit 1
|
||
fi
|
||
|
||
local ver
|
||
ver=$("$JAVA17_HOME/bin/java" -version 2>&1 | head -1)
|
||
if ! echo "$ver" | grep -q 'version "17'; then
|
||
err "JAVA17_HOME 下不是 JDK 17: $ver"
|
||
exit 1
|
||
fi
|
||
log "JDK 17 确认: $ver"
|
||
|
||
# ---- 导出 ----
|
||
export JAVA_HOME="$JAVA17_HOME"
|
||
export ANDROID_SDK_ROOT
|
||
# 把 JDK 17 的 bin 放 PATH 首位,同时加入 platform-tools
|
||
export PATH="$JAVA_HOME/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH"
|
||
|
||
# ---- 检查 gradlew ----
|
||
cd "$PROJECT_DIR"
|
||
if [ ! -f gradlew ]; then
|
||
setup_gradle_wrapper
|
||
fi
|
||
|
||
# ---- 构建 ----
|
||
info "开始构建 $BUILD_TYPE APK ..."
|
||
|
||
# 关键: -Dorg.gradle.java.home 强制 Gradle 使用 JDK 17
|
||
local gradle_args=(
|
||
"-Dorg.gradle.java.home=$JAVA_HOME"
|
||
"--no-daemon"
|
||
)
|
||
|
||
if [ "$BUILD_TYPE" = "release" ]; then
|
||
warn "Release 需要 keystore,尝试构建 ..."
|
||
./gradlew "${gradle_args[@]}" assembleRelease 2>&1 || true
|
||
else
|
||
./gradlew "${gradle_args[@]}" assembleDebug 2>&1
|
||
fi
|
||
|
||
local rc=$?
|
||
echo ""
|
||
|
||
if [ $rc -ne 0 ]; then
|
||
warn "构建失败 (exit=$rc)"
|
||
warn "常见原因:"
|
||
warn " - 网络超时 → 重试"
|
||
warn " - 内存不足 → 加 --no-daemon 重试"
|
||
warn "重试: cd $PROJECT_DIR && JAVA_HOME=$JAVA_HOME ./gradlew -Dorg.gradle.java.home=\$JAVA_HOME --no-daemon assembleDebug"
|
||
return
|
||
fi
|
||
|
||
local apks
|
||
apks=$(find "$PROJECT_DIR/app/build/outputs/apk" -name "*.apk" 2>/dev/null)
|
||
if [ -n "$apks" ]; then
|
||
log "构建成功!"
|
||
echo "$apks" | while read -r f; do
|
||
echo " $(ls -lh "$f" | awk '{print $5, $NF}')"
|
||
done
|
||
else
|
||
warn "未找到 APK 输出"
|
||
fi
|
||
}
|
||
|
||
# ──────────────────────────────────────────────
|
||
# 主流程
|
||
# ──────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
|
||
echo -e "${CYAN} AirDisplay -- Codespaces APK 构建脚本${NC}"
|
||
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
|
||
echo ""
|
||
echo " 项目目录: $PROJECT_DIR"
|
||
echo " SDK 路径: $ANDROID_SDK_ROOT"
|
||
echo " 构建类型: $BUILD_TYPE"
|
||
echo " 系统 java: $(java -version 2>&1 | head -1)"
|
||
echo ""
|
||
|
||
install_jdk
|
||
install_sdk
|
||
setup_local_properties
|
||
setup_gradle_wrapper
|
||
build_apk
|
||
|
||
echo ""
|
||
local_apk="$PROJECT_DIR/app/build/outputs/apk/debug/app-debug.apk"
|
||
if [ -f "$local_apk" ]; then
|
||
log "APK 已就绪: $local_apk"
|
||
echo " 安装: adb install -r $local_apk"
|
||
else
|
||
echo -e "${YELLOW}提示: 若因网络超时失败,重试即可${NC}"
|
||
echo -e "${YELLOW} cd $PROJECT_DIR && ./build.codespace.sh${NC}"
|
||
fi
|
||
echo ""
|