name: Android Build & Publish # 仅在 android-* 分支 push 时触发 (如 android/release, android-1.0) # 构建 release APK (keystore 签名) 并上传到 Gitea Generic Package Registry on: push: branches: - 'android-*' jobs: build-android: runs-on: ubuntu-latest # 需要写权限: 上传 packages permissions: contents: read packages: write env: # 固定工具链版本, 便于 actions/cache 命中 # Android 后端地址 (bake 进 APK); 与 scripts/wsl/build-apk.sh 保持一致 VITE_API_BASE: http://bh.vps.honor3.com:3001 steps: - name: Checkout uses: https://gitea.com/actions/checkout@v4 - name: Setup Node uses: https://gitea.com/actions/setup-node@v4 with: node-version: 22 cache: 'npm' - name: Setup JDK 17 uses: https://gitea.com/actions/setup-java@v4 with: distribution: temurin java-version: '17' # ---------- 缓存: 命中后跳过下面的安装 ---------- - name: Cache Android SDK & NDK id: cache-android uses: https://gitea.com/actions/cache@v4 with: path: ~/android-sdk key: android-sdk-ndk-27.2-${{ runner.os }} - name: Cache Rust toolchain id: cache-rust uses: https://gitea.com/actions/cache@v4 with: path: | ~/.cargo ~/.rustup # 工具链升级时 bump 版本号使缓存失效重装 (含 cargo-ndk) key: rust-android-v1-${{ runner.os }} - name: Cache Tauri cargo target uses: https://gitea.com/actions/cache@v4 with: path: src-tauri/target key: tauri-target-android-${{ runner.os }} # ---------- 安装工具链 (仅缓存未命中时) ---------- - name: Install Rust + Android targets if: steps.cache-rust.outputs.cache-hit != 'true' run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable echo "$HOME/.cargo/bin" >> $GITHUB_PATH . "$HOME/.cargo/env" rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android cargo install cargo-ndk --locked - name: Install Android SDK & NDK if: steps.cache-android.outputs.cache-hit != 'true' run: | export ANDROID_HOME="$HOME/android-sdk" sudo apt-get update sudo apt-get install -y --no-install-recommends unzip mkdir -p "$ANDROID_HOME/cmdline-tools" wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdline-tools.zip unzip -q /tmp/cmdline-tools.zip -d /tmp/ mv /tmp/cmdline-tools "$ANDROID_HOME/cmdline-tools/latest" export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$PATH" yes | sdkmanager --licenses >/dev/null || true sdkmanager --install \ "platforms;android-36" \ "build-tools;36.0.0" \ "platform-tools" \ "ndk;27.2.12479018" \ "cmake;3.22.1" - name: Install frontend deps run: npm ci --no-audit --no-fund # ---------- 全局 Android 环境 (对后续所有 step 生效, 无论缓存是否命中) ---------- - name: Set Android env run: | echo "ANDROID_HOME=$HOME/android-sdk" >> "$GITHUB_ENV" echo "ANDROID_NDK_HOME=$HOME/android-sdk/ndk/27.2.12479018" >> "$GITHUB_ENV" echo "$HOME/android-sdk/cmdline-tools/latest/bin" >> "$GITHUB_PATH" echo "$HOME/android-sdk/platform-tools" >> "$GITHUB_PATH" # ---------- 构建 ---------- - name: Init Android project run: | cd src-tauri npx tauri android init --ci - name: Inject release signing config run: bash scripts/ci/android-signing.sh env: ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} - name: Build release APK run: | export ANDROID_HOME="$HOME/android-sdk" export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.2.12479018" export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH" export CARGO_HOME="$HOME/.cargo" . "$HOME/.cargo/env" cd src-tauri npx tauri android build --apk # 断言签名配置仍在且 release 块实际引用了它 (防止 tauri 重新生成 gen/android 或正则未命中) if ! grep -q 'create("release")' gen/android/app/build.gradle.kts || ! grep -q 'signingConfig = signingConfigs.getByName("release")' gen/android/app/build.gradle.kts; then echo "ERROR: 构建后签名配置丢失/未生效, APK 未签名" >&2 exit 1 fi - name: Locate APK id: apk run: | # 优先 universal 已签名 APK, 找不到再回退到其他已签名 APK APK="" UNIVERSAL=$(find src-tauri/gen/android/app/build/outputs/apk/universal/release -name '*.apk' ! -name '*unsigned*' 2>/dev/null | head -1) if [ -n "$UNIVERSAL" ]; then APK="$UNIVERSAL" else APK=$(find src-tauri/gen/android/app/build/outputs/apk -name '*.apk' ! -name '*unsigned*' | head -1) fi if [ -z "$APK" ]; then echo "ERROR: 未找到已签名 APK" >&2 exit 1 fi echo "path=$APK" >> $GITHUB_OUTPUT ls -lh "$APK" # ---------- 上传到 Gitea Generic Package ---------- - name: Publish APK to Gitea packages env: # 注意: 不能用 GITEA_TOKEN (内置 job token, 无组织 packages 写权限, 且命名规则禁止 GITEA_ 前缀) # 用一个自定义名 secret 存放有 packages 写权限的 user token PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }} APK_PATH: ${{ steps.apk.outputs.path }} run: | set -euo pipefail # 包版本: 用分支名去掉 android- 前缀 + 短 SHA, 保证每次 push 唯一 BRANCH="${GITHUB_REF_NAME#android-}" PKG_VERSION="${BRANCH}-${GITHUB_SHA:0:8}" FILE_NAME="iboard-$(basename "$APK_PATH")" OWNER="${GITHUB_REPOSITORY_OWNER}" PKG_NAME="iboard" # Gitea Generic Package Registry 上传端点 (PUT) # 注意: GITHUB_SERVER_URL 是仓库 web 根地址, 例如 http://git.honor3.com URL="${GITHUB_SERVER_URL}/api/packages/${OWNER}/generic/${PKG_NAME}/${PKG_VERSION}/${FILE_NAME}" echo "上传到: ${URL}" curl -sS --fail-with-body \ -H "Authorization: token ${PACKAGE_TOKEN}" \ --upload-file "$APK_PATH" \ "${URL}" echo "" echo "已发布: ${URL}"