Files

193 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
# ============================================================
# 星元智灵 APK 手动编译脚本 (无 Gradle)
# 使用 Android SDK 命令行工具: aapt / javac / d8 / zipalign / apksigner
# ============================================================
set -e
# ---- 路径配置 ----
PROJECT="$(cd "$(dirname "$0")" && pwd)"
SDK="$HOME/Library/Android/sdk"
BT="$SDK/build-tools/34.0.0"
PLATFORM="$SDK/platforms/android-28/android.jar"
SRC="$PROJECT/app/src/main"
BUILD="$PROJECT/build"
KEYSTORE="$PROJECT/keystore/zhitou-debug.keystore"
APK_BASENAME="xingyuan-zhiling"
STORE_PASS="android"
KEY_PASS="android"
KEY_ALIAS="androiddebugkey"
# ---- 工具路径 ----
AAPT="$BT/aapt"
D8="$BT/d8"
ZIPALIGN="$BT/zipalign"
APKSIGNER="$BT/apksigner"
NDK_VERSION="27.3.13750724"
NDK="$SDK/ndk/$NDK_VERSION"
ARM_CLANGXX="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang++"
# ---- 输出目录 ----
OUT="$BUILD/out"
GEN="$BUILD/gen"
CLASSES="$BUILD/classes"
DEX="$BUILD/dex"
echo "=========================================="
echo " 星元智灵 APK 编译"
echo "=========================================="
echo "SDK: $SDK"
echo "BuildTools: 34.0.0"
echo "Platform: android-28"
echo "Project: $PROJECT"
echo ""
# ---- 恢复超过 Git 单文件限制的人脸模型 ----
"$PROJECT/scripts/restore-face-models.sh"
# ---- Debug 签名证书 ----
if [ ! -f "$KEYSTORE" ]; then
echo "未找到 debug keystore,正在生成: $KEYSTORE"
mkdir -p "$(dirname "$KEYSTORE")"
keytool -genkeypair \
-keystore "$KEYSTORE" \
-storepass "$STORE_PASS" \
-keypass "$KEY_PASS" \
-alias "$KEY_ALIAS" \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-dname "CN=Android Debug,O=Xingyuan Zhiling,C=CN" >/dev/null
fi
# ---- Step 1: 清理 ----
echo "[1/8] 清理旧的编译产物..."
rm -rf "$GEN" "$CLASSES" "$DEX"
mkdir -p "$GEN" "$CLASSES" "$DEX" "$OUT"
# ---- Step 2: 生成 R.java ----
echo "[2/8] 生成 R.java..."
"$AAPT" package -f -m \
-J "$GEN" \
-M "$SRC/AndroidManifest.xml" \
-S "$SRC/res" \
-A "$SRC/assets" \
-I "$PLATFORM"
# ---- Step 3: 收集 Java 源文件 ----
echo "[3/8] 收集 Java 源文件..."
SRC_FILES=$(find "$SRC/java" "$GEN" -name "*.java" | tr '\n' ' ')
echo " 源文件数量: $(echo $SRC_FILES | wc -w | tr -d ' ')"
# ---- Step 4: 编译 Java ----
echo "[4/8] 编译 Java 源码..."
javac --release 8 -parameters \
-classpath "$PLATFORM" \
-sourcepath "$GEN" \
-d "$CLASSES" \
$SRC_FILES 2>&1
echo " 编译完成"
# ---- Step 5: 转换为 DEX ----
echo "[5/8] 转换为 DEX..."
CLASS_FILES=$(find "$CLASSES" -name "*.class" | tr '\n' ' ')
"$D8" \
--output "$DEX" \
--lib "$PLATFORM" \
$CLASS_FILES 2>&1
echo " DEX 生成完成: $DEX/classes.dex"
# ---- Step 6: 打包资源 + Manifest + Assets ----
echo "[6/8] 打包 APK (资源 + Manifest + Assets)..."
rm -f "$OUT/$APK_BASENAME-unsigned.apk" "$OUT/$APK_BASENAME-aligned.apk" "$OUT/$APK_BASENAME-signed.apk"
"$AAPT" package -f \
-M "$SRC/AndroidManifest.xml" \
-S "$SRC/res" \
-A "$SRC/assets" \
-I "$PLATFORM" \
-F "$OUT/$APK_BASENAME-unsigned.apk"
# ---- Step 7: 添加 DEX 和 Native 库 ----
echo "[7/8] 添加 DEX 和 Native 库到 APK..."
# 添加 classes.dex
cd "$DEX"
zip -j "$OUT/$APK_BASENAME-unsigned.apk" classes.dex
cd "$PROJECT"
# 构建 SeetaFace6 JNI 桥(官方 Android 库就位后自动启用)
FACE_LIB_DIR="$SRC/jniLibs/armeabi-v7a"
FACE_JNI_SOURCE="$SRC/cpp/face_engine_jni.cpp"
FACE_JNI_OUTPUT="$FACE_LIB_DIR/libxingyuan_face.so"
FACE_REQUIRED_LIBS=(
libTenniS.so
libSeetaAuthorize.so
libSeetaFaceDetector600.so
libSeetaFaceLandmarker600.so
libSeetaFaceRecognizer600.so
)
FACE_LIBS_READY=true
for library in "${FACE_REQUIRED_LIBS[@]}"; do
if [ ! -f "$FACE_LIB_DIR/$library" ]; then
FACE_LIBS_READY=false
fi
done
if [ "$FACE_LIBS_READY" = true ] && [ -x "$ARM_CLANGXX" ]; then
echo " 编译 SeetaFace6 JNI 桥..."
"$ARM_CLANGXX" \
--sysroot="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" \
-std=c++11 -O2 -fPIC -shared -static-libstdc++ \
-I"$SRC/cpp/include" \
"$FACE_JNI_SOURCE" \
-L"$FACE_LIB_DIR" \
-lSeetaFaceDetector600 \
-lSeetaFaceLandmarker600 \
-lSeetaFaceRecognizer600 \
-lSeetaAuthorize \
-lTenniS \
-llog -lz -ldl -lm \
-o "$FACE_JNI_OUTPUT"
else
rm -f "$FACE_JNI_OUTPUT"
echo " ⚠ SeetaFace6 官方 Android 动态库尚未齐备,人脸 JNI 暂不打包"
fi
# 添加 native 库 (APK 中需要 lib/<abi>/ 结构)
NATIVE_STAGING="$BUILD/native_staging"
rm -rf "$NATIVE_STAGING"
mkdir -p "$NATIVE_STAGING/lib/armeabi-v7a"
find "$SRC/jniLibs/armeabi-v7a" -maxdepth 1 -type f -name "*.so" -exec cp {} "$NATIVE_STAGING/lib/armeabi-v7a/" \;
cd "$NATIVE_STAGING"
zip -r "$OUT/$APK_BASENAME-unsigned.apk" lib/
cd "$PROJECT"
echo " APK 打包完成"
# ---- Step 8: Zipalign + 签名 ----
echo "[8/8] Zipalign 并签名..."
# Zipalign
"$ZIPALIGN" -f 4 "$OUT/$APK_BASENAME-unsigned.apk" "$OUT/$APK_BASENAME-aligned.apk"
# 签名
"$APKSIGNER" sign \
--ks "$KEYSTORE" \
--ks-pass "pass:$STORE_PASS" \
--ks-key-alias "$KEY_ALIAS" \
--key-pass "pass:$KEY_PASS" \
--out "$OUT/$APK_BASENAME-signed.apk" \
"$OUT/$APK_BASENAME-aligned.apk"
# 验证签名
"$APKSIGNER" verify --verbose "$OUT/$APK_BASENAME-signed.apk" 2>&1
# ---- 完成 ----
echo ""
echo "=========================================="
echo " ✅ 编译成功!"
echo "=========================================="
echo ""
ls -lh "$OUT/$APK_BASENAME-signed.apk"
echo ""
echo "输出文件: $OUT/$APK_BASENAME-signed.apk"
echo ""
echo "安装命令:"
echo " adb install -r $OUT/$APK_BASENAME-signed.apk"