From 6c7866f0c13b93b23ab2a6854f302f9c3bc5e7a0 Mon Sep 17 00:00:00 2001 From: xjbsteven Date: Sat, 20 Jun 2026 23:10:21 +0800 Subject: [PATCH] ci: add cloud workflow to build APK with custom MAA Core Build Android MAA Core from a fork/ref in GitHub Actions, deploy into MAA-Meow, and upload a debug/release APK artifact. Ignore local .build-tools/. Co-authored-by: Cursor --- .github/workflows/build-custom-maa-core.yml | 150 ++++++++++++++++++++ .gitignore | 3 + scripts/deploy_local_maa_core.py | 84 +++++++++++ 3 files changed, 237 insertions(+) create mode 100644 .github/workflows/build-custom-maa-core.yml create mode 100644 scripts/deploy_local_maa_core.py diff --git a/.github/workflows/build-custom-maa-core.yml b/.github/workflows/build-custom-maa-core.yml new file mode 100644 index 000000000..9cdcd8718 --- /dev/null +++ b/.github/workflows/build-custom-maa-core.yml @@ -0,0 +1,150 @@ +name: Build APK with Custom MAA Core + +# Cloud pipeline for testing custom MAA Core (e.g. facility_preset PR): +# Job 1: build Android arm64 MAA Core from a fork/ref +# Job 2: deploy Core into MAA-Meow and assemble APK + +on: + workflow_dispatch: + inputs: + maa_repo: + description: 'MAA fork (owner/repo) containing your Core changes' + required: true + default: 'xjbsteven/MaaAssistantArknights' + maa_ref: + description: 'MAA git ref to build (branch/tag/commit)' + required: true + default: 'dev-v2' + build_type: + description: 'APK build type' + required: true + default: 'debug' + type: choice + options: + - debug + - release + +jobs: + build-maa-core: + name: Build MAA Android Core + runs-on: macos-latest + outputs: + core_version: ${{ steps.meta.outputs.core_version }} + steps: + - name: Checkout MAA + uses: actions/checkout@v4 + with: + repository: ${{ inputs.maa_repo }} + ref: ${{ inputs.maa_ref }} + + - name: Fetch MaaUtils submodule + run: git submodule update --init --depth 1 src/MaaUtils + + - name: Resolve Core version label + id: meta + run: | + ver="$(git describe --tags --match 'v*' HEAD 2>/dev/null || echo "local-$(git rev-parse --short HEAD)")" + echo "core_version=${ver}" >> "$GITHUB_OUTPUT" + echo "Core version label: ${ver}" + + - name: Bootstrap MaaDeps (arm64-android) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python3 tools/maadeps-download.py arm64-android + + - name: Setup Android NDK + id: setup-ndk + uses: nttld/setup-ndk@v1 + with: + ndk-version: r29 + + - name: Configure, build and install (arm64) + run: | + cmake -B build --preset android-publish-arm64 \ + -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup-ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake \ + -DMAA_HASH_VERSION='${{ steps.meta.outputs.core_version }}' + cmake --build build --parallel $(sysctl -n hw.logicalcpu) + cmake --install build --prefix install + + - name: Download MaaFramework control unit + uses: robinraju/release-downloader@v1 + with: + repository: MaaXYZ/MaaFramework + latest: true + fileName: "*android-aarch64*.zip" + extract: true + out-file-path: MaaFramework-temp + + - name: Copy MaaAndroidNativeControlUnit + run: cp MaaFramework-temp/bin/libMaaAndroidNativeControlUnit.so install/ + + - name: Upload MAA Core install tree + uses: actions/upload-artifact@v4 + with: + name: maa-android-arm64-install + path: install/ + compression-level: 6 + + build-apk: + name: Build MAA-Meow APK + needs: build-maa-core + runs-on: macos-latest + steps: + - name: Checkout MAA-Meow + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download custom MAA Core + uses: actions/download-artifact@v4 + with: + name: maa-android-arm64-install + path: maa-install + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: '25' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install NDK and CMake + run: sdkmanager --install "ndk;29.0.13113456" "cmake;3.22.1" + + - name: Deploy custom MAA Core into project + run: | + python scripts/deploy_local_maa_core.py \ + --install-dir "$GITHUB_WORKSPACE/maa-install" \ + --abi arm64-v8a \ + --version "${{ needs.build-maa-core.outputs.core_version }}" + + - name: Print MAA Resource version + run: cat app/src/main/assets/MaaSync/MaaResource/version.json + + - name: Build Debug APK + if: inputs.build_type == 'debug' + run: | + chmod +x ./gradlew + ./gradlew clean assembleDebug + + - name: Build Release APK + if: inputs.build_type == 'release' + env: + KEYSTORE_PATH: ${{ github.workspace }}/release.jks + KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} + KEY_ALIAS: ${{ secrets.KEY_ALIAS }} + KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} + run: | + echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > release.jks + chmod +x ./gradlew + ./gradlew clean assembleRelease + + - name: Upload APK + uses: actions/upload-artifact@v4 + with: + name: meow-apk-${{ needs.build-maa-core.outputs.core_version }}-${{ inputs.build_type }} + path: | + app/build/outputs/apk/debug/*.apk + app/build/outputs/apk/release/*.apk diff --git a/.gitignore b/.gitignore index 9341789c8..9c7ef50f5 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,6 @@ android/.cxx /app/release /app/debug /gradle/gradle-daemon-jvm.properties + +# Local build toolchain (JDK/NDK downloads for offline builds) +.build-tools/ diff --git a/scripts/deploy_local_maa_core.py b/scripts/deploy_local_maa_core.py new file mode 100644 index 000000000..3ebb1a157 --- /dev/null +++ b/scripts/deploy_local_maa_core.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Deploy a locally built MAA install/ tree into MAA-Meow assets and jniLibs.""" + +from __future__ import annotations + +import argparse +import shutil +import sys +from pathlib import Path + +ASSETS_RESOURCE_DIR = Path("app/src/main/assets/MaaSync/MaaResource") +JNILIBS_DIR = Path("app/src/main/jniLibs") +VERSION_FILE = Path(".maaversion") +EXCLUDE_SO = {"libc++_shared.so"} + + +def deploy(install_dir: Path, project_root: Path, abi: str, version: str) -> None: + if not install_dir.is_dir(): + raise SystemExit(f"[ERROR] install dir not found: {install_dir}") + + resource_src = install_dir / "resource" + if not resource_src.is_dir(): + raise SystemExit(f"[ERROR] resource dir not found: {resource_src}") + + assets_dir = project_root / ASSETS_RESOURCE_DIR + if assets_dir.exists(): + print(f"[DELETE] {assets_dir}") + shutil.rmtree(assets_dir) + assets_dir.mkdir(parents=True, exist_ok=True) + + copied_resource = 0 + for src in resource_src.rglob("*"): + if not src.is_file(): + continue + rel = src.relative_to(resource_src) + dest = assets_dir / rel + dest.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dest) + copied_resource += 1 + + jnilib_dir = project_root / JNILIBS_DIR / abi + jnilib_dir.mkdir(parents=True, exist_ok=True) + for existing in jnilib_dir.glob("*.so"): + if existing.name != "libjnidispatch.so": + existing.unlink() + + copied_so = 0 + for so in install_dir.glob("*.so"): + if so.name in EXCLUDE_SO: + continue + shutil.copy2(so, jnilib_dir / so.name) + copied_so += 1 + + (project_root / VERSION_FILE).write_text(version + "\n", encoding="utf-8") + print(f"[VERSION] {VERSION_FILE}: {version}") + print(f"[DONE] resource={copied_resource} files, so={copied_so} files -> {abi}/") + + +def main() -> None: + parser = argparse.ArgumentParser(description="Deploy local MAA install/ into MAA-Meow") + parser.add_argument( + "--install-dir", + required=True, + help="Path to MAA cmake install/ directory (contains resource/ and *.so)", + ) + parser.add_argument( + "--abi", + default="arm64-v8a", + choices=["arm64-v8a", "x86_64"], + help="Target Android ABI (default: arm64-v8a)", + ) + parser.add_argument( + "--version", + default="local-facility-preset", + help="Version string written to .maaversion", + ) + args = parser.parse_args() + + project_root = Path(__file__).resolve().parent.parent + deploy(Path(args.install_dir).resolve(), project_root, args.abi, args.version) + + +if __name__ == "__main__": + main()