#!/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 # 1.5 拷贝 dist/ 到 Android 工程 assets/, 绕过 Tauri CLI 时这步要做 # Tauri CLI 默认在 android build 前会干这事, 我们走直 gradle 要自己补上 ANDROID_ASSETS="$WIN_PROJECT/src-tauri/gen/android/app/src/main/assets" mkdir -p "$ANDROID_ASSETS" # 清空旧的 (避免上次的残余) find "$ANDROID_ASSETS" -mindepth 1 -maxdepth 1 ! -name dexopt ! -name tauri.conf.json -exec rm -rf {} + cp -r dist/. "$ANDROID_ASSETS/" echo "前端 bundle 已拷贝到 $ANDROID_ASSETS" ls -la "$ANDROID_ASSETS" | head -10 # 2. 走不同路径 cd src-tauri # 全部 4 个 Android 架构的 rustBuild 任务 (Tauri 2 默认会编 4 个) RUST_BUILD_TASKS=( ":app:rustBuildArm64Release" ":app:rustBuildArmRelease" ":app:rustBuildX86_64Release" ":app:rustBuildX86Release" ) 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" # Gradle 配了 signingConfig 就输出 app-universal-release.apk, # 否则输出 app-universal-release-unsigned.apk, 按文件名判断是否已签名 SIGNED_APK="$APK_DIR/app-universal-release.apk" UNSIGNED_APK="$APK_DIR/app-universal-release-unsigned.apk" if [ -f "$SIGNED_APK" ]; then APK_PATH="$SIGNED_APK" APK_STATUS="已签名" elif [ -f "$UNSIGNED_APK" ]; then APK_PATH="$UNSIGNED_APK" APK_STATUS="未签名" else APK_PATH="" APK_STATUS="未找到" fi echo echo "=== 产物 ($APK_STATUS) ===" if [ -n "$APK_PATH" ]; then ls -lh "$APK_PATH" else ls -lh "$APK_DIR"/*.apk 2>/dev/null || echo "(未找到 APK)" fi if [ "$APK_STATUS" = "已签名" ]; then echo echo "=== 安装到设备 ===" echo " adb install -r $APK_PATH" elif [ "$APK_STATUS" = "未签名" ]; then 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_PATH" fi 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