#!/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 ""