Build OpenCode Android #48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build OpenCode Android | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| opencode_version: | |
| description: 'OpenCode version' | |
| required: false | |
| default: '1.3.13' | |
| abis: | |
| description: 'ABIs to build (comma separated)' | |
| required: false | |
| default: 'armeabi-v7a' | |
| push: | |
| tags: | |
| - 'v*' | |
| env: | |
| BUN_VERSION: "1.2.13" | |
| OPENCODE_VERSION: "1.3.13" | |
| ANDROID_API: "24" | |
| ANDROID_NDK_VERSION: "28.1.13356709" | |
| WEBKIT_COMMIT: "017930ebf915121f8f593bef61cbbca82d78132d" | |
| ICU_VERSION: "75.1" | |
| ZIG_VERSION: "0.16.0" | |
| TINYCC_COMMIT: "b91835d8701523e895a2b447713630069514e291" | |
| JOBS: "2" | |
| jobs: | |
| build-binary: | |
| name: Build opencode (${{ matrix.abi }}) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 360 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| abi: ["armeabi-v7a"] | |
| outputs: | |
| opencode_version: ${{ env.OPENCODE_VERSION }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set ABI | |
| run: | | |
| echo "TARGET_ABI=${{ matrix.abi }}" >> $GITHUB_ENV | |
| SLUG="${{ matrix.abi }}" | |
| SLUG="${SLUG//-/_}" | |
| echo "ABI_SLUG=${SLUG}" >> $GITHUB_ENV | |
| - name: Override OpenCode version | |
| if: github.event.inputs.opencode_version | |
| run: echo "OPENCODE_VERSION=${{ github.event.inputs.opencode_version }}" >> $GITHUB_ENV | |
| - name: Restore main dependency cache | |
| id: cache-restore | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: | | |
| build-${{ env.ABI_SLUG }}/deps-android/prefix | |
| build-${{ env.ABI_SLUG }}/webkit-android | |
| build-${{ env.ABI_SLUG }}/opentui-lib | |
| build-${{ env.ABI_SLUG }}/dist | |
| key: opencode-main-${{ env.ABI_SLUG }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| restore-keys: | | |
| opencode-main-${{ env.ABI_SLUG }}- | |
| opencode-v2-${{ env.ABI_SLUG }}- | |
| - name: Restore Bun build cache | |
| id: cache-restore-bun | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: | | |
| build-${{ env.ABI_SLUG }}/bun-build | |
| build-${{ env.ABI_SLUG }}/bun-src/vendor | |
| key: opencode-bun-${{ env.ABI_SLUG }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| restore-keys: | | |
| opencode-bun-${{ env.ABI_SLUG }}- | |
| - name: Install system packages | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| ninja-build python3 ruby perl \ | |
| git curl wget unzip xz-utils zip file \ | |
| build-essential pkg-config \ | |
| libxml2-dev libxslt1-dev \ | |
| golang-go \ | |
| bison flex gperf \ | |
| autoconf automake libtool | |
| - name: Install CMake 3.28+ | |
| run: | | |
| if cmake --version 2>/dev/null | grep -q "3\.[2-9][0-9]"; then | |
| echo "CMake ok"; cmake --version | |
| else | |
| CMAKE_VER="3.28.6" | |
| cd /tmp | |
| wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-linux-x86_64.tar.gz" -O cmake.tar.gz | |
| sudo tar xzf cmake.tar.gz -C /opt/ | |
| sudo ln -sf "/opt/cmake-${CMAKE_VER}-linux-x86_64/bin/cmake" /usr/local/bin/cmake | |
| fi | |
| - name: Install Android NDK r28b | |
| run: | | |
| NDK_DIR="/opt/android-ndk" | |
| if [ ! -d "$NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64" ]; then | |
| cd /tmp | |
| wget -q "https://dl.google.com/android/repository/android-ndk-r28b-linux.zip" -O ndk.zip | |
| sudo mkdir -p /opt | |
| sudo unzip -q ndk.zip -d /opt/ | |
| sudo mv /opt/android-ndk-r28b "$NDK_DIR" | |
| rm ndk.zip | |
| fi | |
| echo "ANDROID_NDK_HOME=$NDK_DIR" >> $GITHUB_ENV | |
| echo "$NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH | |
| - name: Install Rust + Android targets | |
| run: | | |
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | |
| source "$HOME/.cargo/env" | |
| rustup target add aarch64-linux-android | |
| rustup target add armv7-linux-androideabi | |
| echo "$HOME/.cargo/bin" >> $GITHUB_PATH | |
| - name: Install host Bun | |
| run: | | |
| # Pin to the same version as the Android bun (BUN_VERSION): bun.sh/install | |
| # otherwise pulls the latest 1.3.x, whose standalone format embeds the | |
| # module graph in an ELF .bun section (no EOF trailer), breaking | |
| # build-opencode-android.ts's append-at-EOF module graph extraction. | |
| curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" | |
| export PATH="$HOME/.bun/bin:$PATH" | |
| echo "$HOME/.bun/bin" >> $GITHUB_PATH | |
| bun --version | |
| - name: Install host Zig | |
| run: | | |
| cd /tmp | |
| wget -q "https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-linux-${ZIG_VERSION}.tar.xz" -O zig.tar.xz | |
| tar xf zig.tar.xz | |
| # Zig resolves its install dir from the binary's realpath and needs its | |
| # lib/ tree next to it. Copy the whole tree to /opt/zig, symlink bin. | |
| sudo mkdir -p /opt/zig | |
| sudo cp -r "zig-x86_64-linux-${ZIG_VERSION}/." /opt/zig/ | |
| sudo ln -sf /opt/zig/zig /usr/local/bin/zig | |
| zig version | |
| - name: Apply patches (bun, webkit, opentui) | |
| run: | | |
| chmod +x scripts/*.sh | |
| source scripts/env.sh | |
| ./scripts/apply-patches.sh | |
| - name: Build ICU | |
| run: | | |
| source scripts/env.sh | |
| ./scripts/build-icu.sh | |
| - name: Build WebKit/JSC | |
| run: | | |
| source scripts/env.sh | |
| ./scripts/build-webkit.sh | |
| - name: Build TinyCC | |
| run: | | |
| source scripts/env.sh | |
| ./scripts/build-tinycc.sh | |
| - name: Build OpenTUI | |
| run: | | |
| source scripts/env.sh | |
| ./scripts/build-opentui.sh | |
| - name: Build Bun | |
| run: | | |
| source scripts/env.sh | |
| ./scripts/build-bun.sh | |
| - name: Build OpenCode standalone binary | |
| run: | | |
| source scripts/env.sh | |
| ./scripts/build-opencode.sh | |
| - name: Package + upload | |
| run: | | |
| source scripts/env.sh | |
| # The bundle (bun + opencode) becomes libopencode.so for jniLibs | |
| if [ -f "$DIST_DIR/opencode" ]; then | |
| ABI_SLUG="${{ matrix.abi }}" | |
| mkdir -p dist/jniLibs/${ABI_SLUG} | |
| cp "$DIST_DIR/opencode" "dist/jniLibs/${ABI_SLUG}/libopencode.so" | |
| else | |
| echo "ERROR: dist/opencode missing"; exit 1 | |
| fi | |
| shell: bash | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: opencode-android-${{ matrix.abi }} | |
| path: dist/jniLibs | |
| - name: Save main dependency cache (rolling) | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: | | |
| build-${{ env.ABI_SLUG }}/deps-android/prefix | |
| build-${{ env.ABI_SLUG }}/webkit-android | |
| build-${{ env.ABI_SLUG }}/opentui-lib | |
| build-${{ env.ABI_SLUG }}/dist | |
| key: opencode-main-${{ env.ABI_SLUG }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| - name: Save Bun build cache (rolling) | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: | | |
| build-${{ env.ABI_SLUG }}/bun-build | |
| build-${{ env.ABI_SLUG }}/bun-src/vendor | |
| key: opencode-bun-${{ env.ABI_SLUG }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| build-apk: | |
| name: Build APK (arm64-v8a + armeabi-v7a) | |
| needs: build-binary | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/libs | |
| merge-multiple: true | |
| - name: Copy jniLibs into APK source set | |
| run: | | |
| mkdir -p android/app/src/main/jniLibs | |
| # Artifacts may merge as <abi>/libopencode.so or flat libopencode.so; | |
| # map each found binary into its ABI-specific jniLibs dir. | |
| find /tmp/libs -name 'libopencode.so' -print0 | while IFS= read -r -d '' f; do | |
| rel="${f#/tmp/libs/}" | |
| case "$rel" in | |
| arm64-v8a*) abi="arm64-v8a" ;; | |
| armeabi-v7a*) abi="armeabi-v7a" ;; | |
| *) abi="$(basename "$(dirname "$f")")" ;; | |
| esac | |
| mkdir -p "android/app/src/main/jniLibs/$abi" | |
| cp "$f" "android/app/src/main/jniLibs/$abi/libopencode.so" | |
| echo "placed: $abi/libopencode.so" | |
| done | |
| find android/app/src/main/jniLibs -type f -exec ls -la {} \; | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| - name: Build APK | |
| uses: gradle/actions/setup-gradle@v4 | |
| with: | |
| gradle-version: "8.9" | |
| - name: Gradle assemble | |
| working-directory: android | |
| run: | | |
| # System gradle from setup-gradle above (wrapper .bat is Windows-only; .sh not committed). | |
| gradle --no-daemon assembleDebug | |
| - name: Upload APK | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: opencode-apk | |
| path: android/app/build/outputs/apk/debug/*.apk |