#!/usr/bin/env bash # iBoard Android APK 打包 # 用法: bash scripts/wsl/build-apk.sh [debug|release] # release 模式自动构建 4 个 ABI 并出 universal APK set -euo pipefail WIN_PROJECT='/mnt/d/workbench/iboard' cd "$WIN_PROJECT" VARIANT="${1:-debug}" echo "构建变体: $VARIANT" # 环境变量 export ANDROID_HOME="${ANDROID_HOME:-$HOME/android-sdk}" export ANDROID_NDK_HOME="${ANDROID_NDK_HOME:-$ANDROID_HOME/ndk/27.2.12479018}" # 关键: 把 NDK toolchain bin 加进 PATH, .cargo/config.toml 里 # linker = "aarch64-linux-android24-clang" 这种短名才能被解析到 NDK_TOOLCHAIN_BIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin" if [ ! -d "$NDK_TOOLCHAIN_BIN" ]; then echo "ERROR: NDK toolchain bin 不存在: $NDK_TOOLCHAIN_BIN" echo "请确认 ANDROID_NDK_HOME 正确指向 NDK 27.2.x 目录" exit 1 fi export PATH="$NDK_TOOLCHAIN_BIN:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$HOME/.cargo/bin:$PATH" # 0. 首次需要 android 工程 cd src-tauri if [ ! -d "gen/android" ]; then echo "=== 0. 初始化 Android 工程 (一次性) ===" npx tauri android init fi cd "$WIN_PROJECT" # Android 后端地址, 写到前端 bundle 里 (覆盖默认的 /api 相对路径) export VITE_API_BASE="${VITE_API_BASE:-http://bh.vps.honor3.com:3001}" echo "VITE_API_BASE=$VITE_API_BASE" # 1. 先构建前端, 让 Tauri android 工程能拿到 dist/ echo "=== 1. 构建前端 ===" npm run build # 2. 走不同路径 cd src-tauri # 全部 4 个 Android 架构的 rustBuild 任务 (Tauri 2 默认会编 4 个) RUST_BUILD_TASKS=( ":app:rustBuildArm64Release" ":app:rustBuildArmv7Release" ":app:rustBuildX86_64Release" ":app:rustBuildI686Release" ) SKIP_ARGS=() for t in "${RUST_BUILD_TASKS[@]}"; do SKIP_ARGS+=(-x "${t#:}"); done # 4 个 Android 目标的 cargo target triple ANDROID_TARGETS=( "aarch64-linux-android" "armv7-linux-androideabi" "x86_64-linux-android" "i686-linux-android" ) if [ "$VARIANT" = "release" ]; then echo "[release] 手工 cargo 编 lib (4 个 ABI), gradle 只跑 packaging (跳过 rustBuild* 避免 --release 重复 bug)" for target in "${ANDROID_TARGETS[@]}"; do echo " [cargo] build lib release for $target ..." cargo build \ --target "$target" \ --features custom-protocol \ --lib \ --release done echo " [gradle] assembleRelease -x rustBuild* ..." cd gen/android ./gradlew --no-daemon assembleRelease "${SKIP_ARGS[@]}" APK_DIR="$WIN_PROJECT/src-tauri/gen/android/app/build/outputs/apk/universal/release" echo echo "=== 产物 (未签名) ===" ls -lh "$APK_DIR"/*.apk 2>/dev/null || echo "(未找到 APK)" echo echo "=== Release 签名 (按需) ===" echo "1. 生成 keystore (一次性):" echo " keytool -genkey -v -keystore ~/iboard-release.keystore -alias iboard -keyalg RSA -keysize 2048 -validity 10000" echo "2. 在 ~/.gradle/gradle.properties 写:" echo " IBOARD_UPLOAD_STORE_FILE=/home/$(whoami)/iboard-release.keystore" echo " IBOARD_UPLOAD_KEY_ALIAS=iboard" echo " IBOARD_UPLOAD_STORE_PASSWORD=..." echo " IBOARD_UPLOAD_KEY_PASSWORD=..." echo "3. 重跑本脚本 (Gradle 读 gradle.properties 里的 IBOARD_UPLOAD_* 自动用 releaseSigning)" echo echo "=== 临时用 debug keystore 手动签 (仅测试) ===" echo " \$ANDROID_HOME/build-tools/*/apksigner sign --ks ~/.android/debug.keystore \\" echo " --ks-pass pass:android --key-pass pass:android \\" echo " $APK_DIR/app-universal-release-unsigned.apk" else echo "[debug] Tauri CLI debug 路径 (不传 --release 不会触发 bug), 直接走" npx tauri android build --apk APK_DIR="$WIN_PROJECT/src-tauri/target/debug/bundle/android/app/build/outputs/apk/debug" echo echo "=== 产物 ===" ls -lh "$APK_DIR"/*.apk 2>/dev/null || echo "(未找到 APK)" fi