From 87d1110a8755891e195b5d6efbf132c64ab6fa29 Mon Sep 17 00:00:00 2001 From: mofeng-git Date: Sun, 24 May 2026 09:45:06 +0000 Subject: [PATCH] =?UTF-8?q?ci:=20=E8=B0=83=E6=95=B4=20GitHub=20Actions=20?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E4=B8=8E=E5=8F=91=E5=B8=83=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 126 +++++++++++++++++++++++++++++++++++- android/gradlew | 0 build/build-android.sh | 45 ++++++++++--- 3 files changed, 162 insertions(+), 9 deletions(-) mode change 100644 => 100755 android/gradlew diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47b26c5f..32e749ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -139,9 +139,126 @@ jobs: if-no-files-found: error retention-days: 7 + android: + runs-on: ubuntu-22.04 + needs: frontend + timeout-minutes: 240 + steps: + - uses: actions/checkout@v4 + + - name: Download frontend dist + uses: actions/download-artifact@v4 + with: + name: web-dist + path: web/dist + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Android Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache/android + key: android-buildx-${{ runner.os }}-${{ hashFiles('build/cross/Dockerfile.android') }} + restore-keys: | + android-buildx-${{ runner.os }}- + + - name: Build Android Docker image + uses: docker/build-push-action@v6 + with: + context: build/cross + file: build/cross/Dockerfile.android + tags: one-kvm-android-build:ci + load: true + cache-from: type=local,src=/tmp/.buildx-cache/android + cache-to: type=local,dest=/tmp/.buildx-cache/android-new,mode=max + + - name: Rotate Android Docker layer cache + run: | + rm -rf /tmp/.buildx-cache/android + mv /tmp/.buildx-cache/android-new /tmp/.buildx-cache/android + + - name: Cache Android build dependencies + uses: actions/cache@v4 + with: + path: | + .github/android-cache/gradle + .github/android-cache/cargo-registry + .github/android-cache/cargo-git + .tmp/android-ffmpeg-check + .tmp/android-turbojpeg-src + .tmp/android-libyuv-src + .tmp/android-alsa-src + .tmp/android-opus-src + dist/android-ffmpeg-mediacodec + dist/android-turbojpeg + dist/android-libyuv + dist/android-alsa + dist/android-opus + key: android-deps-${{ runner.os }}-${{ hashFiles('android/**/*.gradle.kts', 'android/gradle/wrapper/gradle-wrapper.properties', 'android/native/Cargo.lock', 'Cargo.lock', 'scripts/build-android-*.sh') }} + restore-keys: | + android-deps-${{ runner.os }}- + + - name: Prepare Android FFmpeg source + run: | + chmod +x android/gradlew + if [ ! -x .tmp/android-ffmpeg-check/src/ffmpeg-rockchip/configure ]; then + rm -rf .tmp/android-ffmpeg-check/src + mkdir -p .tmp/android-ffmpeg-check/src + wget -q https://files.mofeng.run/src/image/other/ffmpeg.tar.gz -O .tmp/android-ffmpeg-check/ffmpeg.tar.gz + tar -xzf .tmp/android-ffmpeg-check/ffmpeg.tar.gz -C .tmp/android-ffmpeg-check/src --strip-components=1 + fi + + - name: Build Android APK + env: + ONE_KVM_ANDROID_DOCKER_IMAGE: one-kvm-android-build:ci + ONE_KVM_ANDROID_SKIP_DOCKER_BUILD: "1" + ONE_KVM_ANDROID_GRADLE_CACHE_DIR: ${{ github.workspace }}/.github/android-cache/gradle + ONE_KVM_ANDROID_CARGO_REGISTRY_CACHE_DIR: ${{ github.workspace }}/.github/android-cache/cargo-registry + ONE_KVM_ANDROID_CARGO_GIT_CACHE_DIR: ${{ github.workspace }}/.github/android-cache/cargo-git + run: bash build/build-android.sh all + + - name: Fix Android build permissions + if: ${{ always() }} + run: | + paths=( + .github/android-cache + .tmp/android-ffmpeg-check + .tmp/android-turbojpeg-src + .tmp/android-libyuv-src + .tmp/android-alsa-src + .tmp/android-opus-src + dist/android-ffmpeg-mediacodec + dist/android-turbojpeg + dist/android-libyuv + dist/android-alsa + dist/android-opus + target/android + android/.gradle + android/app/build + android/native/target + ) + existing=() + for path in "${paths[@]}"; do + if [ -e "$path" ]; then + existing+=("$path") + fi + done + if [ "${#existing[@]}" -gt 0 ]; then + sudo chown -R "$USER:$USER" "${existing[@]}" + fi + + - name: Upload Android APK + uses: actions/upload-artifact@v4 + with: + name: one-kvm-android-apk + path: target/android/*.apk + if-no-files-found: error + retention-days: 7 + release: runs-on: ubuntu-22.04 - needs: [deb, windows] + needs: [deb, windows, android] if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_release }} timeout-minutes: 30 permissions: @@ -166,6 +283,12 @@ jobs: name: one-kvm-windows-exe path: release-artifacts/windows + - name: Download Android artifact + uses: actions/download-artifact@v4 + with: + name: one-kvm-android-apk + path: release-artifacts/android + - name: Publish GitHub Release uses: softprops/action-gh-release@v2 with: @@ -175,3 +298,4 @@ jobs: files: | release-artifacts/deb/*.deb release-artifacts/windows/*.exe + release-artifacts/android/*.apk diff --git a/android/gradlew b/android/gradlew old mode 100644 new mode 100755 diff --git a/build/build-android.sh b/build/build-android.sh index df803b12..68bd75ac 100644 --- a/build/build-android.sh +++ b/build/build-android.sh @@ -17,9 +17,25 @@ fail() { build_android() { local arch="$1" local docker_build_args=() + local docker_mount_args=() local gradle_distribution_url="${ONE_KVM_GRADLE_DISTRIBUTION_URL:-}" local gradle_distribution_url_cn="${ONE_KVM_GRADLE_DISTRIBUTION_URL_CN:-https://mirrors.cloud.tencent.com/gradle/gradle-9.1.0-bin.zip}" local gradle_network_timeout="${ONE_KVM_GRADLE_NETWORK_TIMEOUT:-120000}" + local gradle_cache="${ONE_KVM_ANDROID_GRADLE_CACHE_DIR:-one-kvm-android-gradle-cache}" + local cargo_registry_cache="${ONE_KVM_ANDROID_CARGO_REGISTRY_CACHE_DIR:-one-kvm-android-cargo-registry}" + local cargo_git_cache="${ONE_KVM_ANDROID_CARGO_GIT_CACHE_DIR:-one-kvm-android-cargo-git}" + + add_cache_mount() { + local source="$1" + local target="$2" + + if [[ "$source" == /* || "$source" == ./* || "$source" == ../* ]]; then + mkdir -p "$source" + source="$(cd "$source" && pwd)" + fi + + docker_mount_args+=("-v" "$source:$target") + } if [[ "${CHINAMIRRO:-}" == "1" ]]; then docker_build_args+=("--build-arg" "CHINAMIRRO=1") @@ -28,18 +44,25 @@ build_android() { fi fi - echo "=== Building Android image: $IMAGE_NAME ===" - docker build \ - -f "$DOCKERFILE" \ - -t "$IMAGE_NAME" \ - "${docker_build_args[@]}" \ - "$PROJECT_ROOT/build/cross" + if [[ "${ONE_KVM_ANDROID_SKIP_DOCKER_BUILD:-0}" == "1" ]]; then + echo "=== Skipping Android image build: $IMAGE_NAME ===" + else + echo "=== Building Android image: $IMAGE_NAME ===" + docker build \ + -f "$DOCKERFILE" \ + -t "$IMAGE_NAME" \ + "${docker_build_args[@]}" \ + "$PROJECT_ROOT/build/cross" + fi + + add_cache_mount "$gradle_cache" "/root/.gradle" + add_cache_mount "$cargo_registry_cache" "/root/.cargo/registry" + add_cache_mount "$cargo_git_cache" "/root/.cargo/git" echo "=== Building Android APK: $arch ===" docker run --rm \ -v "$PROJECT_ROOT:/workspace" \ - -v one-kvm-android-gradle-cache:/root/.gradle \ - -v one-kvm-android-cargo-registry:/root/.cargo/registry \ + "${docker_mount_args[@]}" \ -w /workspace \ -e "CHINAMIRRO=${CHINAMIRRO:-0}" \ -e "ONE_KVM_GRADLE_DISTRIBUTION_URL=$gradle_distribution_url" \ @@ -78,6 +101,12 @@ Examples: CHINAMIRRO=1 build/build-android.sh all CHINAMIRRO=1 ONE_KVM_GRADLE_DISTRIBUTION_URL=https://mirrors.aliyun.com/macports/distfiles/gradle/gradle-9.1.0-bin.zip build/build-android.sh all +Environment: + ONE_KVM_ANDROID_GRADLE_CACHE_DIR Host Gradle cache path or Docker volume name + ONE_KVM_ANDROID_CARGO_REGISTRY_CACHE_DIR Host Cargo registry cache path or Docker volume name + ONE_KVM_ANDROID_CARGO_GIT_CACHE_DIR Host Cargo git cache path or Docker volume name + ONE_KVM_ANDROID_SKIP_DOCKER_BUILD=1 Reuse an already loaded Docker image + APK output: target/android/ EOF