Files
pangolin/app/kernel/build-android.sh
T
wangjia 618332906c feat(kernel): 搭建 app/kernel/ 构建管线 (AAR/XCFramework/桌面二进制)
新增 app/kernel/ 目录,包含四个文件:

- VERSION: 固定三个锚点 — sing-box v1.13.12、Go 1.24.3、
  gomobile v0.0.0-20240604150348-70c4c5da7d30;禁止脚本内硬编码

- build-android.sh: gomobile bind → dist/android/libbox.aar
  targets: arm64-v8a / armeabi-v7a / x86_64,-androidapi 21
  build tags: with_quic,with_utls,with_clash_api,with_gvisor(对齐 SFA)
  裁剪注释保留,幂等+--force 支持

- build-ios.sh: gomobile bind → dist/ios/Libbox.xcframework
  targets: ios + iossimulator(device+sim 双 slice)
  build tags 对齐 SFI;含 iOS NE 内存上限敏感说明(裁 grpc/gvisor 指引)

- fetch-desktop-bin.sh: 从 GitHub Release 下载桌面二进制
  支持 linux/darwin/windows × amd64/arm64
  从官方 checksums.txt 做 SHA256 校验;Windows 额外取 wintun.dll
  幂等:产物+校验文件均存在则跳过

dist/ 和 .build/ 加入 gitignore;所有脚本通过 shellcheck -S warning

任务: tsk_d8KmVEzJTCjl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:30:56 +08:00

134 lines
6.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# build-android.sh — gomobile bind sing-box libbox → dist/android/libbox.aar
#
# 用法: ./build-android.sh [--force]
# --force 忽略已有产物,强制重新构建
#
# 依赖:
# - Go : VERSION 中 GO_VERSION 指定的版本($GOROOT 或 PATH 中的 go
# - gomobile: 脚本自动安装至 $GOPATH/bin,依赖 GOMOBILE_VERSION
# - Android NDK: 需设置 ANDROID_NDK_HOME 或 ANDROID_HOME(含 ndk-bundle/ndk/<ver>
#
# 产物: dist/android/libbox.aar
# 包含三个 ABI: arm64-v8a / armeabi-v7a / x86_64
#
# Build tags 说明(对齐官方 SFA — sing-box for Android:
# with_quic — QUIC/HTTP3 协议支持(Hysteria2 必须)
# with_utls — uTLS 指纹模拟(TLS 防检测)
# with_clash_api — Clash 兼容 API(面板控制必须)
# with_gvisor — gVisor TUN 网络栈(高性能 TUN 回退)
#
# 裁剪开关(按需取消注释):
# with_grpc — gRPC 入站(约 +4 MB so 体积)
# with_ech — TLS ECH 扩展(约 +0.5 MB
# with_wireguard — WireGuard 出站(约 +2 MB
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ── 加载版本锚点 ─────────────────────────────────────────────────────────────
# shellcheck source=VERSION
. "${SCRIPT_DIR}/VERSION"
# ── 参数解析 ─────────────────────────────────────────────────────────────────
FORCE=false
for arg in "$@"; do
case "${arg}" in
--force) FORCE=true ;;
*) printf 'Unknown argument: %s\n' "${arg}" >&2; exit 1 ;;
esac
done
# ── 路径配置 ─────────────────────────────────────────────────────────────────
DIST_DIR="${SCRIPT_DIR}/dist/android"
OUT_AAR="${DIST_DIR}/libbox.aar"
BUILD_SRC="${SCRIPT_DIR}/.build/singbox"
# ── Build tags ────────────────────────────────────────────────────────────────
BUILD_TAGS="with_quic,with_utls,with_clash_api,with_gvisor"
# 取消注释以增加功能(会增大 .so 体积):
# BUILD_TAGS="${BUILD_TAGS},with_grpc"
# BUILD_TAGS="${BUILD_TAGS},with_ech"
# BUILD_TAGS="${BUILD_TAGS},with_wireguard"
# ── 幂等检查 ─────────────────────────────────────────────────────────────────
if [[ "${FORCE}" == false && -f "${OUT_AAR}" ]]; then
printf '✓ %s 已存在,跳过构建(传 --force 强制重建)\n' "${OUT_AAR}"
exit 0
fi
# ── 前置检查 ─────────────────────────────────────────────────────────────────
printf '==> 检查前置依赖…\n'
if ! command -v go >/dev/null 2>&1; then
printf '✗ go 未找到,请安装 Go %s\n' "${GO_VERSION}" >&2
exit 1
fi
if ! command -v git >/dev/null 2>&1; then
printf '✗ git 未找到\n' >&2
exit 1
fi
ACTUAL_GO="$(go version | awk '{print $3}' | sed 's/go//')"
printf ' Go 版本: %s(期望 %s\n' "${ACTUAL_GO}" "${GO_VERSION}"
if [[ -n "${ANDROID_NDK_HOME:-}" ]]; then
printf ' NDK: %s\n' "${ANDROID_NDK_HOME}"
elif [[ -n "${ANDROID_HOME:-}" ]]; then
printf ' Android SDK: %sgomobile 将自动定位 NDK\n' "${ANDROID_HOME}"
else
printf '⚠ 未设置 ANDROID_NDK_HOME / ANDROID_HOMEgomobile init 可能失败\n' >&2
fi
# ── 安装 gomobile ─────────────────────────────────────────────────────────────
printf '==> 安装 gomobile@%s…\n' "${GOMOBILE_VERSION}"
go install "golang.org/x/mobile/cmd/gomobile@${GOMOBILE_VERSION}"
go install "golang.org/x/mobile/cmd/gobind@${GOMOBILE_VERSION}"
printf '==> gomobile init…\n'
gomobile init
# ── 准备 sing-box 源码 ────────────────────────────────────────────────────────
printf '==> 准备 sing-box %s 源码…\n' "${SINGBOX_VERSION}"
EXISTING_TAG=""
if [[ -d "${BUILD_SRC}/.git" ]]; then
EXISTING_TAG="$(git -C "${BUILD_SRC}" describe --tags --exact-match 2>/dev/null)" || EXISTING_TAG="unknown"
fi
if [[ "${EXISTING_TAG}" == "${SINGBOX_VERSION}" ]]; then
printf ' 源码已是 %s,跳过克隆\n' "${SINGBOX_VERSION}"
else
if [[ -d "${BUILD_SRC}" ]]; then
printf ' 已有源码版本 %s ≠ %s,清理后重新克隆…\n' "${EXISTING_TAG}" "${SINGBOX_VERSION}"
rm -rf "${BUILD_SRC}"
fi
mkdir -p "${BUILD_SRC%/*}"
git clone --depth 1 --branch "${SINGBOX_VERSION}" \
https://github.com/SagerNet/sing-box.git "${BUILD_SRC}"
fi
# ── 构建 AAR ──────────────────────────────────────────────────────────────────
printf '==> 构建 libbox.aar\n'
printf ' target : android/arm64,android/arm,android/amd64\n'
printf ' api : 21\n'
printf ' tags : %s\n' "${BUILD_TAGS}"
mkdir -p "${DIST_DIR}"
(
cd "${BUILD_SRC}"
go mod download
gomobile bind \
-target android/arm64,android/arm,android/amd64 \
-androidapi 21 \
-tags "${BUILD_TAGS}" \
-o "${OUT_AAR}" \
./experimental/libbox
)
printf '\n✓ 构建完成: %s\n' "${OUT_AAR}"
printf ' ABI 验证(.so 文件列表):\n'
unzip -l "${OUT_AAR}" | grep -E '\.so$' | awk '{print " " $NF}' || true