diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e15bf3f92..51c67139f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,8 @@ on: - main paths: - 'nb4a.properties' +env: + MIERU_VERSION: v3.34.0 jobs: libcore: name: Native Build (LibCore) @@ -32,11 +34,35 @@ jobs: - name: Native Build if: steps.cache.outputs.cache-hit != 'true' run: ./run lib core + mieru: + name: Native Build (Mieru) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru + - name: Install Golang + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/setup-go@v6 + with: + go-version: '1.24.9' + - name: Mieru Build + if: steps.cache.outputs.cache-hit != 'true' + run: ./run lib mieru build: name: Build OSS APK runs-on: ubuntu-latest needs: - libcore + - mieru steps: - name: Checkout uses: actions/checkout@v5 @@ -50,6 +76,23 @@ jobs: path: | app/libs/libcore.aar key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }} + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: mieru-cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru + - name: Verify Mieru Artifacts + run: | + for abi in arm64-v8a armeabi-v7a x86 x86_64; do + if [ ! -f "app/executableSo/$abi/libmieru.so" ]; then + echo "Error: missing app/executableSo/$abi/libmieru.so (Mieru cache miss)" >&2 + exit 1 + fi + done - name: Gradle cache uses: actions/cache@v5 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a816079f..b7a4868d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,8 @@ on: branches: - '*' pull_request: +env: + MIERU_VERSION: v3.34.0 jobs: libcore: name: Native Build (LibCore) @@ -37,11 +39,35 @@ jobs: - name: Native Build if: steps.cache.outputs.cache-hit != 'true' run: ./run lib core + mieru: + name: Native Build (Mieru) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru-ci + - name: Install Golang + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/setup-go@v6 + with: + go-version: '1.24.9' + - name: Mieru Build + if: steps.cache.outputs.cache-hit != 'true' + run: ./run lib mieru build: name: Build OSS APK runs-on: ubuntu-latest needs: - libcore + - mieru steps: - name: Checkout uses: actions/checkout@v5 @@ -60,6 +86,23 @@ jobs: path: | app/libs/libcore.aar key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }}-ci + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: mieru-cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru-ci + - name: Verify Mieru Artifacts + run: | + for abi in arm64-v8a armeabi-v7a x86 x86_64; do + if [ ! -f "app/executableSo/$abi/libmieru.so" ]; then + echo "Error: missing app/executableSo/$abi/libmieru.so (Mieru cache miss)" >&2 + exit 1 + fi + done - name: Gradle cache uses: actions/cache@v5 with: diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index c59e303ae..10257facd 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -2,6 +2,8 @@ name: Preview Build on: workflow_dispatch: inputs: +env: + MIERU_VERSION: v3.34.0 jobs: libcore: name: Native Build (LibCore) @@ -28,11 +30,35 @@ jobs: - name: Native Build if: steps.cache.outputs.cache-hit != 'true' run: ./run lib core + mieru: + name: Native Build (Mieru) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru + - name: Install Golang + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/setup-go@v6 + with: + go-version: '1.24.9' + - name: Mieru Build + if: steps.cache.outputs.cache-hit != 'true' + run: ./run lib mieru build: name: Build OSS APK runs-on: ubuntu-latest needs: - libcore + - mieru steps: - name: Checkout uses: actions/checkout@v5 @@ -46,6 +72,23 @@ jobs: path: | app/libs/libcore.aar key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }} + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: mieru-cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru + - name: Verify Mieru Artifacts + run: | + for abi in arm64-v8a armeabi-v7a x86 x86_64; do + if [ ! -f "app/executableSo/$abi/libmieru.so" ]; then + echo "Error: missing app/executableSo/$abi/libmieru.so (Mieru cache miss)" >&2 + exit 1 + fi + done - name: Gradle cache uses: actions/cache@v5 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2252e059d..1279b68f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,8 @@ on: publish: description: "Publish: If want ignore" required: false +env: + MIERU_VERSION: v3.34.0 jobs: libcore: name: Native Build (LibCore) @@ -34,11 +36,35 @@ jobs: - name: Native Build if: steps.cache.outputs.cache-hit != 'true' run: ./run lib core + mieru: + name: Native Build (Mieru) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru + - name: Install Golang + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/setup-go@v6 + with: + go-version: '1.24.9' + - name: Mieru Build + if: steps.cache.outputs.cache-hit != 'true' + run: ./run lib mieru build: name: Build OSS APK runs-on: ubuntu-latest needs: - libcore + - mieru steps: - name: Checkout uses: actions/checkout@v5 @@ -52,6 +78,23 @@ jobs: path: | app/libs/libcore.aar key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }} + - name: Mieru Status + run: cat buildScript/lib/mieru.sh buildScript/init/env.sh buildScript/init/env_ndk.sh | sha1sum > mieru_status + - name: Mieru Cache + id: mieru-cache + uses: actions/cache@v5 + with: + path: | + app/executableSo + key: ${{ hashFiles('.github/workflows/*', 'mieru_status') }}-${{ env.MIERU_VERSION }}-mieru + - name: Verify Mieru Artifacts + run: | + for abi in arm64-v8a armeabi-v7a x86 x86_64; do + if [ ! -f "app/executableSo/$abi/libmieru.so" ]; then + echo "Error: missing app/executableSo/$abi/libmieru.so (Mieru cache miss)" >&2 + exit 1 + fi + done - name: Gradle cache uses: actions/cache@v5 with: diff --git a/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt b/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt index 5b860b35f..511154ff0 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt @@ -10,7 +10,7 @@ import androidx.core.text.isDigitsOnly object Executable { private val EXECUTABLES = setOf( - "libtrojan.so", "libtrojan-go.so", "libnaive.so", "libtuic.so", "libhysteria.so" + "libtrojan.so", "libtrojan-go.so", "libnaive.so", "libtuic.so", "libhysteria.so", "libmieru.so" ) fun killAll(alsoKillBg: Boolean = false) { diff --git a/app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt b/app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt index 10307a1f7..87cc9fa40 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt @@ -73,6 +73,7 @@ object PluginManager { return when (pluginId) { "hysteria-plugin" -> soIfExist("libhysteria.so") "hysteria2-plugin" -> soIfExist("libhysteria2.so") + "mieru-plugin" -> soIfExist("libmieru.so") else -> null } } diff --git a/buildScript/lib/mieru.sh b/buildScript/lib/mieru.sh new file mode 100755 index 000000000..f0fcc0bbf --- /dev/null +++ b/buildScript/lib/mieru.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# Build the Mieru client binary for all Android ABIs and install them as +# bundled native executables (app/executableSo//libmieru.so). +# +# This lets NekoBox run Mieru profiles without the separate external plugin +# (moe.matsuri.exe.mieru). PluginManager.initNativeInternal resolves +# "mieru-plugin" -> libmieru.so from nativeLibraryDir. +# +# Usage: ./run lib mieru +set -e +set -o pipefail + +source "buildScript/init/env.sh" + +if [ -z "$ANDROID_NDK_HOME" ]; then + echo "Error: ANDROID_NDK_HOME is not set (NDK required to cross-compile Mieru)." >&2 + exit 1 +fi + +# Mieru release tag to build from source. +MIERU_VERSION="${MIERU_VERSION:-v3.34.0}" + +DEPS="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin" +# macOS NDK host dirs are darwin-x86_64 / darwin-arm64; fall back if linux is absent. +if [ ! -d "$DEPS" ]; then + DEPS="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin" +fi +if [ ! -d "$DEPS" ]; then + DEPS="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-arm64/bin" +fi +if [ ! -d "$DEPS" ]; then + echo "Error: NDK LLVM toolchain not found under $ANDROID_NDK_HOME (unsupported host or NDK layout)." >&2 + exit 1 +fi + +WORK="$(pwd)/.mieru-build" +OUT="$(pwd)/app/executableSo" + +# Fetch source (shallow clone at the pinned tag). Re-clone fresh if the existing +# checkout is missing or its git operations fail (e.g. corrupted by a prior build). +need_clone=1 +if [ -d "$WORK/.git" ]; then + if git -C "$WORK" fetch --depth 1 origin "refs/tags/$MIERU_VERSION" \ + && git -C "$WORK" checkout -q FETCH_HEAD; then + need_clone=0 + else + echo ">> existing $WORK is unusable; re-cloning" + fi +fi +if [ "$need_clone" -eq 1 ]; then + rm -rf "$WORK" + git clone --depth 1 --branch "$MIERU_VERSION" https://github.com/enfein/mieru.git "$WORK" +fi + +pushd "$WORK" >/dev/null + +build_abi() { + local abi="$1" goarch="$2" cc="$3" goarm="$4" + echo ">> building libmieru.so for $abi" + mkdir -p "$OUT/$abi" + env GOOS=android GOARCH="$goarch" ${goarm:+GOARM=$goarm} CGO_ENABLED=1 \ + CC="$DEPS/$cc" \ + go build -trimpath -ldflags='-s -w' \ + -o "$OUT/$abi/libmieru.so" ./cmd/mieru +} + +build_abi "arm64-v8a" "arm64" "aarch64-linux-android21-clang" +build_abi "armeabi-v7a" "arm" "armv7a-linux-androideabi21-clang" "7" +build_abi "x86" "386" "i686-linux-android21-clang" +build_abi "x86_64" "amd64" "x86_64-linux-android21-clang" + +popd >/dev/null + +echo ">> installed Mieru binaries:" +ls -la "$OUT"/*/libmieru.so