name: Build Android APK on: push: branches: - main paths: - 'apps/web/**' - 'apps/tauri/**' - 'packages/shared/**' - '.github/workflows/android.yml' pull_request: paths: - 'apps/web/**' - 'apps/tauri/**' - 'packages/shared/**' - '.github/workflows/android.yml' workflow_dispatch: env: VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL || 'https://zeavisedu.asepharyana.my.id' }} jobs: build-apk: runs-on: ubuntu-latest timeout-minutes: 45 permissions: contents: write outputs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Cache Bun dependencies uses: actions/cache@v4 with: path: | ~/.bun/install/cache node_modules apps/*/node_modules packages/*/node_modules key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock', '**/package.json') }} restore-keys: | ${{ runner.os }}-bun- - name: Install dependencies run: bun install - name: Setup Java 21 uses: actions/setup-java@v4 with: distribution: temurin java-version: '21' - name: Setup Android SDK uses: android-actions/setup-android@v3 with: packages: 'platforms;android-36 build-tools;36.0.0' - name: Pin NDK version run: echo "ANDROID_NDK_HOME=${ANDROID_SDK_ROOT}/ndk/$(ls ${ANDROID_SDK_ROOT}/ndk | sort -V | head -1)" >> $GITHUB_ENV - name: Setup Rust with Android targets uses: dtolnay/rust-toolchain@stable with: targets: >- aarch64-linux-android, armv7-linux-androideabi, i686-linux-android, x86_64-linux-android - name: Cache Cargo uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git apps/tauri/target key: ${{ runner.os }}-cargo-android-${{ hashFiles('apps/tauri/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-android- - name: Cache Gradle uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: ${{ runner.os }}-gradle-android-${{ hashFiles('apps/tauri/Cargo.lock') }} restore-keys: | ${{ runner.os }}-gradle-android- - name: Install Tauri CLI run: cd apps/tauri && bun install - name: Compute version id: version run: | # Get latest git tag, default to v0.1.0 LATEST_TAG=$(git tag --list 'v*' --sort=-v:refname | head -1) if [ -z "$LATEST_TAG" ]; then NEW_VERSION="0.1.0" else # Strip 'v' prefix, bump patch BASE="${LATEST_TAG#v}" IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" PATCH=$((PATCH + 1)) NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" fi echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT echo "New version: ${NEW_VERSION}" # Update tauri.conf.json jq --arg v "${NEW_VERSION}" '.version = $v' apps/tauri/tauri.conf.json > /tmp/tauri.conf.json && mv /tmp/tauri.conf.json apps/tauri/tauri.conf.json # Update Cargo.toml sed -i "s/^version = \".*\"/version = \"${NEW_VERSION}\"/" apps/tauri/Cargo.toml echo "Updated tauri.conf.json and Cargo.toml to ${NEW_VERSION}" - name: Init Tauri Android project working-directory: apps/tauri env: JAVA_HOME: ${{ env.JAVA_HOME_21_X64 }} ANDROID_HOME: ${{ env.ANDROID_SDK_ROOT }} NDK_HOME: ${{ env.ANDROID_NDK_HOME }} run: | rm -rf gen/android bun tauri android init - name: Patch AndroidManifest (CAMERA permission) working-directory: apps/tauri run: bash scripts/patch-android-manifest.sh - name: Build Tauri Android APK working-directory: apps/tauri env: JAVA_HOME: ${{ env.JAVA_HOME_21_X64 }} ANDROID_HOME: ${{ env.ANDROID_SDK_ROOT }} NDK_HOME: ${{ env.ANDROID_NDK_HOME }} run: bun tauri android build --apk - name: Decode keystore if: github.event_name != 'pull_request' env: ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} run: | echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > apps/tauri/zeavis.keystore - name: Sign APK if: github.event_name != 'pull_request' env: ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} run: | APK_UNSIGNED=$(find apps/tauri/gen/android/app/build/outputs/apk -name '*.apk' ! -name '*-signed*' | head -1) APK_SIGNED="apps/tauri/gen/android/app/build/outputs/apk/universal/release/zeavis-edu-v${{ steps.version.outputs.version }}.apk" $ANDROID_SDK_ROOT/build-tools/36.0.0/apksigner sign \ --ks apps/tauri/zeavis.keystore \ --ks-pass "pass:${ANDROID_KEYSTORE_PASSWORD}" \ --ks-key-alias "${ANDROID_KEY_ALIAS}" \ --key-pass "pass:${ANDROID_KEY_PASSWORD}" \ --out "$APK_SIGNED" \ "$APK_UNSIGNED" echo "signed_apk=${APK_SIGNED}" >> $GITHUB_ENV echo "Signed APK: $APK_SIGNED" ls -lh "$APK_SIGNED" - name: Create Release and upload APK if: github.event_name != 'pull_request' id: release uses: softprops/action-gh-release@v2 with: tag_name: v${{ steps.version.outputs.version }} name: v${{ steps.version.outputs.version }} body: | ZeaVis Edu Android APK v${{ steps.version.outputs.version }} 📦 Built from ${{ github.sha }} 🔗 Triggered by ${{ github.actor }} ### Install Download the APK below and install on your Android device. 🤖 Generated with [Claude Code](https://claude.com/claude-code) files: | ${{ env.signed_apk }} apps/tauri/gen/android/app/build/outputs/bundle/**/*.aab draft: false prerelease: false